题目描述
G 公司有 \(n\) 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 \(n\) 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
输入格式
文件的第 \(1\) 行中有 \(1\) 个正整数 \(n\) ,表示有 \(n\) 个仓库。
第 \(2\) 行中有 \(n\) 个正整数,表示 \(n\) 个仓库的库存量。
输出格式
输出最少搬运量。
样例
样例输入
5
17 9 14 16 4
样例输出
11
数据范围与提示
\(1 \leq n \leq 100\)
题解
先求出最终状态每个仓库有多少货物
看每个仓库是多了还是少了
如果多了,那么源点向它连边,容量为多出的量,费用为 \(0\)
如果少了,那么它向汇点连边,容量为缺少的量,费用为 \(0\)
相邻的两个点连容量为 \(inf\) 的边,费用为 \(1\) ,代表相邻两点可以移动,但每次移动算作一次费用
但要防止源点流向仓库,直接流向汇点,所以要拆点
每个点拆成两个点,之间不能连边,连边方式就是上面所述,但是与源点连的和与汇点连的不能是同一列点
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100+10,inf=0x3f3f3f3f;
int n,a[MAXN],all,stan,e=1,s,t,beg[MAXN<<1],cur[MAXN<<1],clk,vis[MAXN<<1],nex[MAXN<<4],to[MAXN<<4],cap[MAXN<<4],was[MAXN<<4],answas,p[MAXN<<1],level[MAXN<<1];
std::queue<int> q;
template<typename T> inline void read(T &x)
{T data=0,w=1;char ch=0;while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();if(ch=='-')w=-1,ch=getchar();while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{if(x<0)putchar('-'),x=-x;if(x>9)write(x/10);putchar(x%10+'0');if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y,int z,int k)
{to[++e]=y;nex[e]=beg[x];beg[x]=e;cap[e]=z;was[e]=k;to[++e]=x;nex[e]=beg[y];beg[y]=e;cap[e]=0;was[e]=-k;
}
inline bool bfs()
{for(register int i=1;i<=t;++i)level[i]=inf;level[s]=0;p[s]=1;q.push(s);while(!q.empty()){int x=q.front();q.pop();p[x]=0;for(register int i=beg[x];i;i=nex[i])if(cap[i]&&level[to[i]]>level[x]+was[i]){level[to[i]]=level[x]+was[i];if(!p[to[i]])p[to[i]]=1,q.push(to[i]);}}return level[t]!=inf;
}
inline int dfs(int x,int maxflow)
{if(x==t||!maxflow)return maxflow;int res=0;vis[x]=clk;for(register int &i=cur[x];i;i=nex[i])if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+was[i]){int f=dfs(to[i],min(maxflow,cap[i]));res+=f;cap[i]-=f;cap[i^1]+=f;answas+=was[i]*f;maxflow-=f;if(!maxflow)break;}vis[x]=0;return res;
}
inline void MCMF()
{while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),dfs(s,inf);
}
int main()
{read(n);for(register int i=1;i<=n;++i)read(a[i]),all+=a[i];stan=all/n;s=(n<<1)+1,t=s+1;for(register int i=1;i<=n;++i){if(a[i]-stan>0)insert(s,i,a[i]-stan,0);else insert(i+n,t,stan-a[i],0);int pre=i-1?i-1:n,nxt=i%n+1;insert(i,pre,inf,1);insert(i,nxt,inf,1);insert(i,pre+n,inf,1);insert(i,nxt+n,inf,1);}MCMF();write(answas,'\n');return 0;
}