网络流24题-运输问题
运输问题
时间限制: 2 s
空间限制: 256000 KB
题目描述 Description
W 公司有m个仓库和n 个零售商店。第i 个仓库有ai 个单位的货物;第j 个零售商店需要bj个单位的货物。货物供需平衡,即 sum(si)=sum(bj)。从第i 个仓库运送每单位货物到第j 个零售商店的费用为cij 。试设计一个将仓库中所有货物运送到零售商店的运输方案,使总运输费用最少。
编程任务:
对于给定的m 个仓库和n 个零售商店间运送货物的费用,计算最优运输方案和最差运输方案。
输入描述 Input Description
输入的第1行有2 个正整数m和n,分别表示仓库数和零售商店数。接下来的一行中有m个正整数ai ,1≤i≤m,表示第i个仓库有ai 个单位的货物。再接下来的一行中有n个正整数bj ,1≤j≤n,表示第j个零售商店需要bj 个单位的货物。接下来的m行,每行有n个整数,表示从第i 个仓库运送每单位货物到第j个零售商店的费用cij 。
输出描述 Output Description
将计算出的最少运输费用和最多运输费用输出
样例输入 Sample Input
2 3
220 280
170 120 210
77 39 105
150 186 122
样例输出 Sample Output
48500
69140
费用流。建立超级源点和超级汇点,跑最小费用最大流和最大费用最大流。
最大费用最大流的解法:
1.把所有费用变成相反数跑一遍最小费用最大流,输出答案的相反数。
#include<bits/stdc++.h> #define N 500 #define INF LLONG_MAX/2 using namespace std; struct Edge { long long from,to,flow,cost; }; struct MCMF { vector<Edge> edges; vector<long long > G[N]; long long inq[N];//是否在队列中 long long d[N];//距离 long long p[N];//上一条弧 long long a[N];//可改进量 void init()//初始化 { for(long long i=0; i<N; i++)G[i].clear(); edges.clear(); } void addedge(long long from,long long to,long long flow,long long cost)//加边 { edges.push_back((Edge){from,to,flow,cost}); edges.push_back((Edge){to,from,0,-cost}); long long m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool SPFA(long long s,long long t,long long &flow,long long &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost { for(long long i=0; i<N; i++)d[i]=INF,inq[i]=0; d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<long long > Q; Q.push(s); while(!Q.empty()) { long long u=Q.front(); Q.pop(); inq[u]=0; for(long long i=0; i<G[u].size(); i++) { Edge& e=edges[G[u][i]]; if(e.flow>0 && d[e.to]>d[u]+e.cost)//满足可增广且可变短 { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.flow); if(!inq[e.to]) { inq[e.to]=1; Q.push(e.to); } } } } if(d[t]==INF) return false;//汇点不可达则退出 flow+=a[t]; cost+=d[t]*a[t]; long long u=t; while(u!=s)//更新正向边和反向边 { edges[p[u]].flow-=a[t]; edges[p[u]^1].flow+=a[t]; u=edges[p[u]].from; } return true; } long long MincotMaxflow(long long s,long long t,long long &flow,long long &cost) { while(SPFA(s,t,flow,cost)); } }; MCMF mcmf; int main() { int m,n; int a[N],b[N]; int cost[N][N]; scanf("%d %d",&m,&n); for(int i=1;i<=m;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&b[i]); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&cost[i][j]); mcmf.init(); int s=0,t=n+m+1; for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0); for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],cost[i][j]); long long ans1=0,ans2=0,flow; flow=0; mcmf.MincotMaxflow(s,t,flow,ans1); mcmf.init(); for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0); for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],-cost[i][j]); flow=0; mcmf.MincotMaxflow(s,t,flow,ans2); printf("%lld\n%lld",ans1,-ans2); return 0; }
2.初始化spfa时dis数组全从INF改为-INF,松弛的条件从 dis[i]>dis[j]+cost[i,j]改为dis[i]<dis[j]+cost[i,j] 。
#include<bits/stdc++.h> #define N 500 #define INF LLONG_MAX/2 using namespace std; struct Edge { long long from,to,flow,cost; }; struct MCMF { vector<Edge> edges; vector<long long > G[N]; long long inq[N];//是否在队列中 long long d[N];//距离 long long p[N];//上一条弧 long long a[N];//可改进量 void init()//初始化 { for(long long i=0; i<N; i++)G[i].clear(); edges.clear(); } void addedge(long long from,long long to,long long flow,long long cost)//加边 { edges.push_back((Edge){from,to,flow,cost}); edges.push_back((Edge){to,from,0,-cost}); long long m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool SPFA(long long s,long long t,long long &flow,long long &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost { for(long long i=0; i<N; i++)d[i]=INF,inq[i]=0; d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<long long > Q; Q.push(s); while(!Q.empty()) { long long u=Q.front(); Q.pop(); inq[u]=0; for(long long i=0; i<G[u].size(); i++) { Edge& e=edges[G[u][i]]; if(e.flow>0 && d[e.to]>d[u]+e.cost)//满足可增广且可变短 { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.flow); if(!inq[e.to]) { inq[e.to]=1; Q.push(e.to); } } } } if(d[t]==INF) return false;//汇点不可达则退出 flow+=a[t]; cost+=d[t]*a[t]; long long u=t; while(u!=s)//更新正向边和反向边 { edges[p[u]].flow-=a[t]; edges[p[u]^1].flow+=a[t]; u=edges[p[u]].from; } return true; } long long MincotMaxflow(long long s,long long t,long long &flow,long long &cost) { while(SPFA(s,t,flow,cost)); } bool SPFA2(long long s,long long t,long long &flow,long long &cost)//寻找最大费用的增广路,使用引用同时修改原flow,cost { // printf("%lld\n",cost); for(long long i=0; i<N; i++)d[i]=-INF,inq[i]=0; d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<long long > Q; Q.push(s); while(!Q.empty()) { long long u=Q.front(); Q.pop(); inq[u]=0; for(long long i=0; i<G[u].size(); i++) { Edge& e=edges[G[u][i]]; //printf("%d %d %d\n",e.flow,d[e.to],e.cost+d[u]); if(e.flow>0 && d[e.to]<d[u]+e.cost)//满足可增广且可变短 { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.flow); if(!inq[e.to]) { inq[e.to]=1; Q.push(e.to); } } } } if(d[t]==-INF) return false;//汇点不可达则退出 flow+=a[t]; cost+=d[t]*a[t]; long long u=t; while(u!=s)//更新正向边和反向边 { edges[p[u]].flow-=a[t]; edges[p[u]^1].flow+=a[t]; u=edges[p[u]].from; } return true; } long long MaxcotMaxflow(long long s,long long t,long long &flow,long long &cost) { while(SPFA2(s,t,flow,cost)); } }; MCMF mcmf; int main() { int m,n; int a[N],b[N]; int cost[N][N]; scanf("%d %d",&m,&n); for(int i=1;i<=m;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&b[i]); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) scanf("%d",&cost[i][j]); mcmf.init(); int s=0,t=n+m+1; for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0); for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],cost[i][j]); long long ans1=0,ans2=0,flow; flow=0; mcmf.MaxcotMaxflow(s,t,flow,ans1); mcmf.init(); for(int i=1;i<=m;i++)mcmf.addedge(s,i,a[i],0); for(int i=1;i<=n;i++)mcmf.addedge(m+i,t,b[i],0); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++)mcmf.addedge(i,j+m,a[i],cost[i][j]); flow=0; mcmf.MincotMaxflow(s,t,flow,ans2); printf("%lld\n%lld",ans2,ans1); return 0; }
路漫漫其修远兮,吾将上下而求索