题目描述
GG 公司有 n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 n 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
输入格式
文件的第 1 行中有 1 个正整数 n,表示有 n 个仓库。
第 2 行中有 n 个正整数,表示 n 个仓库的库存量。
输出格式
输出最少搬运量。
输入输出样例
输入
5
17 9 14 16 4
输出
11
说明/提示
1≤n≤100
极其***的我(不拆点要死?)
看到这道题,不难想到,要么直接贪心,要么费用流。
既然是网络流24题,给出费用流做法:
首先建立超级源点S,与超级汇点T,让S到每个仓库连边,费用为0,流量为仓库的库存量。让仓库到T连边,费用为0,流量为所有库存的平均值。(这样可以保证一定是最大流,并且最后库存都一样)。然后让相邻的仓库之间连线,流量为正无穷,费用为1。(注意1和n特判,因为形成了一个环)。
然后可得:最大流保证了库存一样,最小费用保证了最小的搬运量,直接跑一遍费用流即可。
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=410;
const int inf=0x3f3f3f3f;
int n,s,t,a[N],sum,d[N];
int head[N],nex[N<<2],to[N<<2],flow[N<<2],w[N<<2],tot=1;
struct node{
int v,e;
}p[N];
inline void ade(int a,int b,int c,int d){
to[++tot]=b; w[tot]=d; flow[tot]=c; nex[tot]=head[a]; head[a]=tot;
}
inline void add(int a,int b,int c,int d){
ade(a,b,c,d); ade(b,a,0,-d);
}
int spfa(){
memset(d,inf,sizeof d); d[s]=0; queue<int> q; q.push(s);
int vis[N]={0}; vis[s]=1;
while(q.size()){
int u=q.front(); q.pop(); vis[u]=0;
for(int i=head[u];i;i=nex[i]){
if(flow[i]&&d[to[i]]>d[u]+w[i]){
d[to[i]]=d[u]+w[i];
p[to[i]].v=u; p[to[i]].e=i;
if(!vis[to[i]]) q.push(to[i]),vis[to[i]]=1;
}
}
}
return d[t]!=inf;
}
int EK(){
int res=0;
while(spfa()){
int mi=inf;
for(int i=t;i!=s;i=p[i].v) mi=min(mi,flow[p[i].e]);
for(int i=t;i!=s;i=p[i].v){
flow[p[i].e]-=mi; flow[p[i].e^1]+=mi;
}
res+=d[t]*mi;
}
return res;
}
signed main(){
cin>>n; s=0; t=n+1;
for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i]; sum/=n;
for(int i=1;i<=n;i++){
add(s,i,a[i],0); add(i,t,sum,0);
}
for(int i=1;i<=n;i++){
if(i==1) add(i,i+1,inf,1),add(i,n,inf,1);
else if(i==n) add(i,1,inf,1),add(i,i-1,inf,1);
else add(i,i+1,inf,1),add(i,i-1,inf,1);
}
cout<<EK()<<endl;
return 0;
}