[网络流24题] 负载平衡问题 题解

负载平衡问题

题目描述

题目描述
\(\operatorname{G}\) 公司有 \(n\) 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 \(n\) 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
输入格式
第一行一个正整数 \(n\) ,表示有 \(n\) 个仓库。
第二行 \(n\) 个正整数,表示 \(n\) 个仓库的库存量。
输出格式
输出最少搬运量。

题目解析

环形均分纸牌,直接贪心就完了!!!
好吧这是网络流24题,所以我们用网络流做。

首先我们算出每个仓库需要输入和输出的货物数量。
我们建立一个超级源和超级汇。不难发现,如果这个仓库需要输入货物,那么从超级源连一条边到这个点,容量为这个店需要输入的货物的数量,费用为 \(0\)。如果这个点需要输出货物,那么就从这个点到超级源建一条容量为输出货物数量的边,费用为 \(0\) 。然后在相邻的仓库建费用为 \(1\) 容量无穷大的边。
然后跑一次最小费用最大流就可以了,答案显然是费用。

#include<queue>
#include<cstdio>
#include<cstring>
#define I inline
#define db double
#define U unsigned
#define R register
#define ll long long
#define RI register int
#define ull unsigned long long
#define abs(x) ((x)>0?(x):(-(x)))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define Me(a,b) memset(a,b,sizeof(a))
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LL_INF (0x7fffffffffffffff)
#define maxn 139
#define maxm 1039
//#define debug
using namespace std;
#define Type int
I Type read(){
	Type sum=0; int flag=0; char c=getchar();
	while((c<'0'||c>'9')&&c!='-') c=getchar(); if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){ sum=(sum<<1)+(sum<<3)+(c^48); c=getchar(); }
	if(flag) return -sum; return sum;
}
int a[maxn],n,ave,sum;
int head[maxn],nex[maxm],to[maxm],c[maxm],w[maxm],kkk=1;//w flow c cost
#define add(x,y,a,b) nex[++kkk]=head[x]; head[x]=kkk; w[kkk]=a; c[kkk]=b; to[kkk]=y;
int flow[maxn],pre[maxn],dis[maxn],vis[maxn],las[maxn],ret,s,t;
queue<int> q,E;
int spfa(){
	q=E; q.push(s); Me(dis,0x7f); Me(flow,0x7f); pre[t]=-1; dis[s]=0; RI cur,i;
	while(!q.empty()){
		cur=q.front(); q.pop(); vis[cur]=0;
		for(i=head[cur];i;i=nex[i])
			if(w[i]>0&&dis[to[i]]>dis[cur]+c[i]){
				dis[to[i]]=dis[cur]+c[i]; las[to[i]]=i; pre[to[i]]=cur;
				if(!vis[to[i]]) q.push(to[i]),vis[to[i]]=1; flow[to[i]]=min(flow[cur],w[i]);
			}
	}
	return ~pre[t];
}
void mcmf(){
	RI cur;
	while(spfa()){
		cur=t; ret+=dis[t]*flow[t];
		while(cur!=s){ w[las[cur]]-=flow[t]; w[las[cur]^1]+=flow[t]; cur=pre[cur]; }
	} return;
}
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
	RI i; n=read(); for(i=0;i<n;i++) a[i]=read(),sum+=a[i];
	ave=sum/n; for(i=0;i<n;i++) a[i]-=ave; s=n; t=n+1;
	for(i=0;i<n;i++)
		if(a[i]>0){ add(s,i,a[i],0) add(i,s,0,0) }
		else if(a[i]<0){ add(i,t,-a[i],0) add(t,i,0,0) }
	for(i=0;i<n;i++){
		add(i,(i+1)%n,INF,1) add((i+1)%n,i,0,-1)
		add((i+1)%n,i,INF,1) add(i,(i+1)%n,0,-1)
	}
	n+=2; mcmf(); printf("%d",ret); return 0;
}
posted @ 2021-09-02 19:57  jiangtaizhe001  阅读(30)  评论(0编辑  收藏  举报