zoukankan      html  css  js  c++  java
  • 网络流24题之负载平衡问题

    这就是均分纸牌加强版,不过我们要用网络流做。

    看了一下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。最大流满足了所有的盈余和亏损供求平衡,最小费用就是最少搬运量。

    很好写了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=250005,inf=1e9;
     4 int d[N],head[N],cnt=-1,n,a[N],cost,f[N],s,t;
     5 bool v[N];
     6 struct node{
     7     int w,to,nex,c,f;
     8 }e[1000005];
     9 void add(int x,int y,int w,int c)
    10 {
    11     e[++cnt].to=y;e[cnt].nex=head[x];head[x]=cnt;e[cnt].f=x;e[cnt].w=w;e[cnt].c=c;
    12     e[++cnt].to=x;e[cnt].nex=head[y];head[y]=cnt;e[cnt].f=y;e[cnt].w=0;e[cnt].c=-c;
    13 }
    14 queue<int>q;
    15 bool spfa()
    16 {
    17     memset(d,0x3f,sizeof(d));
    18     memset(v,0,sizeof(v));
    19     memset(f,-1,sizeof(f));
    20     v[s]=1;d[s]=0;q.push(s);
    21     while(!q.empty())
    22     {
    23         int x=q.front();q.pop();v[x]=0;
    24         for(int i=head[x];i!=-1;i=e[i].nex)
    25         {
    26             if(!e[i].w||d[e[i].to]<=d[x]+e[i].c)continue;
    27             int y=e[i].to;
    28             d[y]=d[x]+e[i].c;f[y]=i;
    29             if(!v[y])
    30             {
    31                 q.push(y);v[y]=1;
    32             }
    33         }
    34     }
    35     if(d[t]>inf)return 0;
    36     int flow=inf;
    37     for(int i=f[t];i!=-1;i=f[e[i].f])
    38     flow=min(flow,e[i].w);
    39     for(int i=f[t];i!=-1;i=f[e[i].f])
    40     e[i].w-=flow,e[i^1].w+=flow,cost+=flow*e[i].c;
    41     return 1;
    42 }
    43 int main()
    44 {
    45     scanf("%d",&n);int sum=0;memset(head,-1,sizeof(head));
    46     for(int i=1;i<=n;++i)scanf("%d",&a[i]),sum+=a[i];
    47     int ave=sum/n;t=(n<<1)+10;s=0;
    48     for(int i=1;i<=n;++i)a[i]=a[i]-ave;
    49     for(int i=1;i<=n;++i)
    50     {
    51         int x=(i==1)?n:i-1;int y=(i==n)?1:i+1;
    52         if(a[i]<0)add(i<<1|1,t,-a[i],0);
    53         else add(s,i<<1,a[i],0);
    54         add(i<<1,x<<1,inf,1);add(i<<1,y<<1,inf,1);
    55         add(i<<1,(x<<1)|1,inf,1);add(i<<1,(y<<1)|1,inf,1);
    56     }
    57     while(spfa());
    58     printf("%d
    ",cost);
    59     return 0;
    60 }
  • 相关阅读:
    [leetcode] 110. 平衡二叉树
    [leetcode] 109. 有序链表转换二叉搜索树
    [leetcode] 108. 将有序数组转换为二叉搜索树
    [leetcode] 107. 二叉树的层次遍历 II
    [leetcode] 106. 从中序与后序遍历序列构造二叉树
    [leetcode] 105. 从前序与中序遍历序列构造二叉树
    [leetcode] 111. 二叉树的最小深度
    LeetCode
    LeetCode
    LeetCode
  • 原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8413426.html
Copyright © 2011-2022 走看看