题目大意
一个环上有(n)个仓库,每个仓库存储的货物数量不等,如何用最少搬运量可以使 (n) 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
问题解决
貌似这个就是一道奥数题,但是众所周知,(OI)不是(MO)我们考虑用(OI)的方法来解决
每个点中的货物运输很难处理,但是总的数是不变的,而且(n)非常小,我们就可以考虑用费用流来解决这个问题
我们先算出最终状态,也就是(avg= sum /n)
-
建立一个超级原点,和超级汇点
-
对于一个(a[i]-avg>0)的仓库,也就是说需要将货物从这里运走,所以从超级原点建一条到(a[i])的边,流量为(a[i]-avg),费用为(0)
-
对于一个(a[i]-avg<0)的仓库,也就是说需要货物运进来,所以建一条从(a[i])到超级汇点的边,流量为(a[i]-avg),费用为(0)
-
(a[i])之间可以相互运,所以之间建一条边,流量为(INF),费用为(1),注意是环
代码实现
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=105,maxe=605,INF=0x3f3f3f3f;
int N,avg,a[maxn],Ans;
int lnk[maxn],nxt[maxe],son[maxe],w[maxe],c[maxe],cnt=1,st,ed,x[maxn];
int dis[maxn],vis[maxn];
int mincost;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
void add_e(int x,int y,int z,int cost){son[++cnt]=y;w[cnt]=z;c[cnt]=cost;nxt[cnt]=lnk[x];lnk[x]=cnt;}
void add_edge(int x,int y,int z,int cost){add_e(x,y,z,cost);add_e(y,x,0,-cost);}
int spfa(){
queue<int> q;
memset(dis,INF,sizeof dis);
memset(vis,0,sizeof vis);
dis[st]=0;q.push(st);
while(!q.empty()){
int cur=q.front();q.pop();vis[cur]=0;
for(int j=lnk[cur];j;j=nxt[j]){
if(w[j]>0&&dis[son[j]]>dis[cur]+c[j]){
dis[son[j]]=dis[cur]+c[j];
if(!vis[son[j]]){vis[son[j]]=1;q.push(son[j]);}
}
}
}
return dis[ed]!=INF;
}
int DFS(int x,int delta){
if(x==ed)return delta;
vis[x]=1;int flow=0;
for(int j=lnk[x];j;j=nxt[j]){
if(!vis[son[j]]&&w[j]>0&&dis[son[j]]==dis[x]+c[j]){
int tmp=DFS(son[j],min(delta-flow,w[j]));
if(tmp){
mincost+=(c[j]*tmp);
w[j]-=tmp;w[j^1]+=tmp;flow+=tmp;
}
}
}
vis[x]=0;
return flow;
}
int Dinic(){
int maxflow=0;
while(spfa()){
while(1){
int temp=DFS(st,INF);
if(!temp)break;
maxflow+=temp;
}
}
return maxflow;
}
int main(){
N=read();for(int i=1;i<=N;i++) a[i]=read(),avg+=a[i];avg/=N;
st=0;ed=N+1;
for(int i=1;i<=N;i++){x[i]=a[i]-avg;if(x[i]>0)add_edge(st,i,x[i],0);if(x[i]<0)add_edge(i,ed,-x[i],0);}
for(int i=1;i<=N;i++){if(i!=1)add_edge(i,i-1,INF,1);if(i!=N)add_edge(i,i+1,INF,1);}
add_edge(1,N,INF,1);add_edge(N,1,INF,1);
Ans=Dinic();
printf("%d
",mincost);
return 0;
}