傳送門html
很是經典的費用流的模型吧,也能夠經過二分圖最大匹配去作,可是鑑於二分圖最大匹配的算法存在必定的侷限性,故仍是學一學較爲通用的費用流的作法。c++
這道題目中本質上要討論的問題跟運輸問題,運輸問題是一致的。算法
由於考慮到每一個人只能被分配到一種貨物,每種貨物只能被一我的所分配,所以,咱們不妨用流量將他們限流。spa
咱們建立一個超級源地\(sp\),將\(sp\)跟每一個人連一條流量爲\(1\),費用爲\(0\)的邊。code
同時咱們建立一個超級匯點\(ep\),將每一種貨物跟\(ep\)都連一條流量爲\(1\),費用爲\(0\)的邊。htm
同時,對於每個人和貨物,咱們對他們連一條流量爲無窮的邊。blog
由於每一個人只能從超級源點獲取最多\(1\)點的流量,每種貨物只能向超級匯點傳送最多\(1\)點的流量,所以當這個圖滿流時,可以保證每一個人必定會配對最多一個貨物,即達到咱們限流的要求。get
而若是咱們須要求解最小花費,咱們只須要將人和貨物的邊加上的費用取\(val_{ij}\),最後在這張圖上跑最小費用最大流後最小費用即爲答案。it
而若是咱們須要求解最大花費,咱們只須要將人和貨物的邊加上的費用取相反數\(-val_{ij}\),最後在這張圖上跑最小費用最大流後最小費用的相反數即爲答案。class
#include <bits/stdc++.h> #define maxn 4050 using namespace std; struct Node{ int to,next,val,cost; }q[maxn<<1]; int head[maxn],cnt=0; int dis[maxn],vis[maxn],sp,ep,maxflow,cost; int n,num[maxn][maxn]; const int INF=0x3f3f3f3f; void init(){ memset(head,-1,sizeof(head)); cnt=2; maxflow=cost=0; } void addedge(int from,int to,int val,int cost){ q[cnt].to=to; q[cnt].next=head[from]; q[cnt].val=val; q[cnt].cost=cost; head[from]=cnt++; } void add_edge(int from,int to,int val,int cost){ addedge(from,to,val,cost); addedge(to,from,0,-cost); } bool spfa(){ memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[sp]=0; vis[sp]=1; queue<int>que; que.push(sp); while(!que.empty()){ int x=que.front(); que.pop(); vis[x]=0; for(int i=head[x];i!=-1;i=q[i].next){ int to=q[i].to; if(dis[to]>dis[x]+q[i].cost&&q[i].val){ dis[to]=dis[x]+q[i].cost; if(!vis[to]){ que.push(to); vis[to]=1; } } } } return dis[ep]!=0x3f3f3f3f; } int dfs(int x,int flow){ if(x==ep){ vis[ep]=1; maxflow+=flow; return flow; }//能夠到達t,加流 int used=0;//該條路徑可用流量 vis[x]=1; for(int i=head[x];i!=-1;i=q[i].next){ int to=q[i].to; if((vis[to]==0||to==ep)&&q[i].val!=0&&dis[to]==dis[x]+q[i].cost){ int minflow=dfs(to,min(flow-used,q[i].val)); if(minflow!=0){ cost+=q[i].cost*minflow; q[i].val-=minflow; q[i^1].val+=minflow; used+=minflow; } //能夠到達t,加費用,扣流量 if(used==flow)break; } } return used; }int mincostmaxflow(){ while(spfa()){ vis[ep]=1; while(vis[ep]){ memset(vis,0,sizeof(vis)); dfs(sp,INF); } } return maxflow; } int main() { scanf("%d",&n); init(); sp=2*n+1,ep=2*n+2; for(int i=1;i<=n;i++){ add_edge(sp,i,1,0); add_edge(i+n,ep,1,0); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&num[i][j]); add_edge(i,j+n,INF,num[i][j]); } } mincostmaxflow(); printf("%d\n",cost); init(); for(int i=1;i<=n;i++){ add_edge(sp,i,1,0); add_edge(i+n,ep,1,0); } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ add_edge(i,j+n,INF,-num[i][j]); } } mincostmaxflow(); printf("%d\n",-cost); return 0; }