[题解]P4016|负载平衡问题
负载平衡问题
(下文中\(x\xrightarrow{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. 向旁边的两个仓库连边:
\(i\xrightarrow{+\infty,1}i+1,i\xrightarrow{+\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__<<"\n"
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<<"\n";
// fclose(stdin);
// fclose(stdout);
return 0;
}