题目描述
G 公司有 n个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 n个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
输入输出格式
输入格式:
文件的第 1 行中有 1 个正整数 n,表示有 n 个仓库。
第 2 行中有 n 个正整数,表示 n个仓库的库存量。
输出格式:
输出最少搬运量。
样例输入:
5
17 9 14 16 4
样例输出:
11
模拟赛贪心水过,第一道费用流。
所有仓库的数量都相等,就应该讲多余平均值的仓库运往少于平均值的仓库,多的仓库应该贡献,连向源点;少的仓库应该得到,连向汇点,且费用为0(因为费用指在两个相邻仓库中的运输单价)。
下一步,每两个相邻的公司也需要连一条+无穷的边权,费用为1.
之后就没什么了。
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define N 50000 int f[N],cost[N]; int val[N],to[N],head[N],nex[N]; int a[N]; int n; int idx=1; int S,T; int sum; int ans,maxflow; int nowflow[N]; int inq[N]; int pre[N]; void addedge(int a,int b,int c,int d) { nex[++idx]=head[a]; head[a]=idx; to[idx]=b; val[idx]=c; cost[idx]=d; } bool spfa(int S,int T) { memset(f,0x3f,sizeof(f)); memset(nowflow,0x3f,sizeof(nowflow)); memset(inq,0,sizeof(inq)); queue <int > q; f[S]=0; inq[S]=1; q.push(S); while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; for(int i=head[x];i;i=nex[i]) { if(val[i]&&f[to[i]]>f[x]+cost[i]) { f[to[i]]=f[x]+cost[i]; nowflow[to[i]]=min(nowflow[x],val[i]); pre[to[i]]=i; if(!inq[to[i]]) { inq[to[i]]=1; q.push(to[i]); } } } } if(f[T]>=0x3f3f3f3f) return 0; return 1; } void EK() { int x=T; while(x!=S) { int i=pre[x]; val[i]-=nowflow[T]; val[i^1]+=nowflow[T]; x=to[i^1]; } maxflow+=nowflow[T]; ans+=f[T]*nowflow[T]; } int main() { scanf("%d",&n); S=0,T=n+1; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; } sum/=n; for(int i=1;i<=n;i++) { if(sum>a[i]) { addedge(S,i,sum-a[i],0); addedge(i,S,0,0); } else { addedge(i,T,a[i]-sum,0); addedge(T,i,0,0); } } for(int i=2;i<=n;i++) { addedge(i-1,i,1<<30,1); addedge(i,i-1,0,-1); addedge(i,i-1,1<<30,1); addedge(i-1,i,0,-1); } addedge(n,1,1<<30,1); addedge(1,n,0,-1); addedge(1,n,1<<30,1); addedge(n,1,0,-1); while(spfa(S,T)) EK(); printf("%d",ans); }