nefu493負載平衡問題

負載平衡問題

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章