负载平衡问题
(下文中(xxrightarrow{a,b}y)表示从(x)向(y)连一条流量为(a),费用为(b)的边)
在做均分纸牌那题的时候,我们首先求出了牌数的平均值,对与每一堆牌减平均值
这道题同理,
1.货物数减去 (arv) 若大于0
(s xrightarrow{a[i]-arv,0}i)
表示 (i) 可以获得数量为 (a[i]-arv) 的货物
2.货物数减去 (arv) 若小于0
(i xrightarrow{arv-a[i],0}i)
表示 (i) 可以流出数量为 (arv-a[i]) 的货物
3. 向旁边的两个仓库连边:
(ixrightarrow{+infty,1}i+1,ixrightarrow{+infty,1}i-1)
表示 (i) 可以将货物流向 (i+1,i-1)
坠后从(s)到(t)跑最小费用最大流即可
(mathcal{Code}:)
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 575
#define inf 2147483647
#define int long long
#define debug cout<<__LINE__<<" "<<__FUNCTION__<<"
"
inline int read(){
int x=0,y=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*y;
}
struct Edge{
int to,flow,cost,nxt;
}edge[N];
int n,m,s,t,tot=1;
int flow[N],deep[N],last[N],pre[N],vis[N],head[N],a[N];//pre: point last:edge
int maxflow,mincost;
inline void add(int from,int to,int flow,int cost){
edge[++tot].nxt=head[from];
edge[tot].to=to;
edge[tot].flow=flow;
edge[tot].cost=cost;
head[from]=tot;
}
bool spfa(){
memset(flow,0x3f,sizeof(flow));
memset(deep,0x3f,sizeof(deep));
memset(vis,0,sizeof(vis));
deep[s]=0;
pre[t]=-1;
vis[s]=1;
queue<int>q;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u] = 0;
for(int i = head[u];i;i = edge[i].nxt){
int v = edge[i].to;
if(deep[v] > deep[u] + edge[i].cost && edge[i].flow){
flow[v] = min(flow[u],edge[i].flow);
deep[v] = deep[u] + edge[i].cost;
pre[v] = u;last[v] = i;
if(!vis[v]){
vis[v] = 1;q.push(v);
}
}
}
}
return pre[t]!=-1;
}
inline void Dinic(){
while(spfa()){
maxflow += flow[t];
mincost += flow[t] * deep[t];
int x = t;
while(x != s){
edge[last[x]].flow -= flow[t];
edge[last[x] ^ 1].flow += flow[t];
x = pre[x];
}
}
}
signed main(){
// freopen("a.in","r",stdin);
// freopen(".out","w",stdout);
n=read();
s=0;t=n+1;
int sum=0;
for(int i=1;i<=n;i++){
a[i]=read();sum+=a[i];
}
sum/=n;
for(int i=1;i<=n;i++){
a[i]-=sum;
if(a[i]>0) add(s,i,a[i],0),add(i,s,0,0);
if(a[i]<0) add(i,t,-a[i],0),add(t,i,0,0);
}
for(int i=1;i<=n;i++){
add(i,i%n+1,inf,1);add(i%n+1,i,0,-1);
add(i,(i-2+n)%n+1,inf,1);add((i-2+n)%n+1,i,0,-1);
}
Dinic();
cout<<mincost<<"
";
// fclose(stdin);
// fclose(stdout);
return 0;
}