傳送門c++
有\(m\)個倉庫和\(n\)個零售商,第\(i\)個倉庫送到第\(j\)個零售商須要花費\(v[i][j]\)元。如今須要讓倉庫的供給量以及零售商的收穫量相同,問最小花費以及最大花費。spa
至關經典的最小費用最大流的模型。由於要保證供給以及收穫相同,即表明着流量平衡,所以咱們能夠讓超級源點\(sp\)跟對應的倉庫連一條流量爲\(a_i\),費用爲\(0\)的邊,同時讓對應的零售商跟超級匯點\(ep\)連一條流量爲\(b_i\),費用爲\(0\)的邊。而對於倉庫與零售商,咱們只須要將倉庫和零售商之間連一條流量爲無窮,費用爲\(v[i][j]\)的邊。code
對於最小花費問題,咱們只須要在上述的圖中跑最小費用最大流便可。get
而對於最大花費的問題,咱們只須要將上述的圖中的倉庫與零售商的改成連一條流量爲無窮,費用爲\(-v[i][j]\)的邊,最後在新圖上跑一邊最小費用最大流,而最後最小費用的相反數便是答案。it
#include <bits/stdc++.h> using namespace std; const int maxn = 505; const int maxm = 20005; int head[maxn],cnt=0; int dis[maxn],vis[maxn],sp,ep,maxflow,cost; const int INF=0x3f3f3f3f; struct Node{ int to,next,val,cost; }q[maxm<<1]; 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; } 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; } 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 a[maxn],b[maxn],v[maxn][maxn]; int main() { int n,m; init(); scanf("%d%d",&n,&m); sp=n+m+1,ep=n+m+2; for(int i=1;i<=n;i++){ scanf("%d",&a[i]); add_edge(sp,i,a[i],0); } for(int i=1;i<=m;i++){ scanf("%d",&b[i]); add_edge(i+n,ep,b[i],0); } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&v[i][j]); add_edge(i,j+n,INF,v[i][j]); } } mincostmaxflow(); printf("%d\n",cost); init(); for(int i=1;i<=n;i++){ add_edge(sp,i,a[i],0); } for(int i=1;i<=m;i++){ add_edge(i+n,ep,b[i],0); } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ add_edge(i,j+n,INF,-v[i][j]); } } mincostmaxflow(); printf("%d\n",-cost); return 0; }