[网络流24题]code vs 1916 负载平衡问题

1916 负载平衡问题

 时间限制: 2 s
 空间限制: 256000 KB
 题目等级 : 大师 Master
题解
 查看运行结果
题目描述 Description

G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最
少搬运量可以使n 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
«编程任务:
对于给定的n 个环形排列的仓库的库存量,编程计算使n 个仓库的库存数量相同的最少
搬运量。

输入描述 Input Description

第1 行中有1 个正整数n(n<=100),表示有n
个仓库。第2 行中有n个正整数,表示n个仓库的库存量。

输出描述 Output Description

将计算出的最少搬运量输出

样例输入 Sample Input

5
17 9 14 16 4

样例输出 Sample Output

11

题解:
转自hzwer:

【问题分析】

转化为供求平衡问题,用最小费用最大流解决。

【建模方法】

首先求出所有仓库存货量平均值,设第i个仓库的盈余量为A[i],A[i] = 第i个仓库原有存货量 – 平均存货量。建立二分图,把每个仓库抽象为两个节点Xi和Yi。增设附加源S汇T。

1、如果A[i]>0,从S向Xi连一条容量为A[i],费用为0的有向边。
2、如果A[i]<0,从Yi向T连一条容量为-A[i],费用为0的有向边。
3、每个Xi向两个相邻顶点j,从Xi到Xj连接一条容量为无穷大,费用为1的有向边,从Xi到Yj连接一条容量为无穷大,费用为1的有向边。

求最小费用最大流,最小费用流值就是最少搬运量。

【建模分析】

计算出每个仓库的盈余后,可以把问题转化为供求问题。建立供求网络,把二分图X集合中所有节点看做供应节点,Y集合所有节点看做需求节点,在能一次搬运满足供需的Xi和Yj之间连接一条费用为1的有向边,表示搬运一个单位货物费用为1。另外还要在Xi与相邻的Xj之间连接边,表示货物可以暂时搬运过去,不立即满足需求,费用也为1。最大流满足了所有的盈余和亏损供求平衡,最小费用就是最少搬运量。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
int n,point[1000],dis[1000],can[1000],num[1000],laste[1000];
int next[20000],v[20000],remain[20000],tot=-1,a[1000],cost[1000],maxn;
const int inf=1e9;
void add(int x,int y,int z,int k)
{
  tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; cost[tot]=k;
  tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; cost[tot]=-k;
}
int addflow(int s,int t)
{
  int ans=inf; int now=t;
  while(now!=s)
   {
   	ans=min(ans,remain[laste[now]]);
   	now=v[laste[now]^1];
   }
  now=t;
  while(now!=s)
   {
   	remain[laste[now]]-=ans;
   	remain[laste[now]^1]+=ans;
   	now=v[laste[now]^1];
   }
  return ans;
}
bool spfa(int s,int t)
{
  memset(dis,0x7f,sizeof(dis));
  memset(can,0,sizeof(can));
  queue<int> p; p.push(s); dis[s]=0; can[s]=1;
  while(!p.empty())
   {
   	int now=p.front(); p.pop();
   	for (int i=point[now];i!=-1;i=next[i])
   	 if (dis[v[i]]>dis[now]+cost[i]&&remain[i])
   	  {
   	  	dis[v[i]]=dis[now]+cost[i];
   	  	laste[v[i]]=i;
   	  	if (!can[v[i]])
   	  	 {
   	  	 	can[v[i]]=1;
   	  	 	p.push(v[i]);
   	  	 }
   	  }
   	can[now]=0;
   }
  if (dis[t]>inf) return false;
  int k=addflow(s,t);
  maxn+=k*dis[t];
  return true;
}
void maxflow(int s,int t)
{
	while(spfa(s,t));
}
int main()
{
  memset(point,-1,sizeof(point));
  memset(next,-1,sizeof(next));
  scanf("%d",&n);
  int sum=0;
  for (int i=1;i<=n;i++)
   {
   	 int x; scanf("%d",&x); sum+=x;  a[i]=x;
   } 
  sum/=n;
  for (int i=1;i<=n;i++)
    a[i]=sum-a[i];
  for (int i=1;i<=n;i++)
   if (a[i]>0)
    add(0,i,a[i],0);
   else
    add(i+n,2*n+1,-a[i],0);
  for (int i=1;i<=n;i++)
   {
   	 if (i==1)
   	  {
   	  	add(i,i+1,inf,1);
   	  	add(i,i+n+1,inf,1);
   	  	add(i,n,inf,1);
   	  	add(i,n+n,inf,1);
   	  	continue;
   	  }
   	 if (i==n)
   	  {
   	  	add(i,i-1,inf,1);
   	  	add(i,i+n-1,inf,1);
   	  	add(i,1,inf,1);
   	  	add(i,n+1,inf,1);
   	  	continue;
   	  }
   	 add(i,i-1,inf,1);
   	 add(i,i+n-1,inf,1);
   	 add(i,i+1,inf,1);
   	 add(i,i+1+n,inf,1);
   }
  maxflow(0,2*n+1);
  printf("%d",maxn);
  return 0;
}



你可能感兴趣的:([网络流24题]code vs 1916 负载平衡问题)