負載平衡問題
G 公司有n 個沿鐵路運輸線環形排列的倉庫,每個倉庫存儲的貨物數量不等。如何用最少搬運量可以使n 個倉庫的庫存數量相同。搬運貨物時,只能在相鄰的倉庫之間搬運。
對於給定的n 個環形排列的倉庫的庫存量,編程計算使n 個倉庫的庫存數量相同的最少搬運量。
【問題分析】轉化爲供求平衡問題,用最小費用最大流解決。
【建模方法】
首先求出所有倉庫存貨量平均值,設第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 <cstdio>
using namespace std;
const int mm=111111;
const int mn=2222;
const int oo=1000000000;
int node,src,dest,edge;
int reach[mm],flow[mm],cost[mm],next[mm];
int head[mn],dis[mn],q[mn],p[mn];
bool vis[mn];
int a[mn];
inline int min(int a,int b)
{
return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
node=_node,src=_src,dest=_dest;
for(int i=0;i<node;++i)head[i]=-1,vis[i]=0;
edge=0;
}
inline void addedge(int u,int v,int f,int c)
{
reach[edge]=v,flow[edge]=f,cost[edge]=c,next[edge]=head[u],head[u]=edge++;
reach[edge]=u,flow[edge]=0,cost[edge]=-c,next[edge]=head[v],head[v]=edge++;
}
bool spfa()
{
int i,u,v,l,r=0,tmp;
for(i=0;i<node;++i)dis[i]=oo;
dis[q[r++]=src]=0;
p[src]=p[dest]=-1;
for(l=0;l!=r;(++l==mn)?l=0:1)
for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])
if(flow[i]&&dis[v=reach[i]]>(tmp=dis[u]+cost[i]))
{
dis[v]=tmp;
p[v]=i^1;
if(vis[v])continue;
vis[q[r++]=v]=1;
if(r==mn)r=0;
}
return p[dest]>=0;
}
int SpfaFlow()
{
int i,delta,ans=0;
while(spfa())
{
for(i=p[dest],delta=oo;i>=0;i=p[reach[i]])
delta=min(delta,flow[i^1]);
for(i=p[dest];i>=0;i=p[reach[i]])
flow[i]+=delta,flow[i^1]-=delta;
ans+=delta*dis[dest];
}
return ans;
}
int main()
{
int n,i,ave,sum,j;
while(~scanf("%d",&n))
{
sum=0;
prepare(n+n+2,0,n+n+1);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
ave=sum/n;
for(i=1;i<=n;i++)
a[i]=a[i]-ave;
for(i=1;i<=n;i++)
{
if(a[i]>=0)
addedge(src,i,a[i],0);
else
addedge(i+n,dest,-a[i],0);
}
for(i=1;i<=n;i++)
{
if(i==1)
{
addedge(i,n+2,oo,1);
addedge(i,n+n,oo,1);
addedge(i,2,oo,1);
addedge(i,n,oo,1);
}
else if(i==n)
{
addedge(i,n+1,oo,1);
addedge(i,n+n-1,oo,1);
addedge(i,1,oo,1);
addedge(i,n-1,oo,1);
}
else
{
addedge(i,i+1+n,oo,1);
addedge(i,i+1,oo,1);
addedge(i,i-1+n,oo,1);
addedge(i,i-1,oo,1);
}
}
printf("%d\n",SpfaFlow());
}
return 0;
}