[网络流24题]

https://www.luogu.org/problemnew/show/P4016

题目描述

GGG 公司有 nnn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 nnn 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。

输入输出格式

输入格式:

文件的第 1 行中有 1 个正整数 n,表示有 n 个仓库。

2 行中有 n 个正整数,表示 n 个仓库的库存量。

输出格式:

输出最少搬运量。

 输入输出样例

输入样例#1: 
5
17 9 14 16 4
输出样例#1:
11
说明

1<=n<=100

题解:1)建图,设置超级源点0和超级汇点(n+1),源点向每个高于平均值的点连一条流量为差值,费用为0的边,并弄一条流量为0且费用为0的反向边(用于回退,也是求网络流的要点),每个低于平均值的点向汇点连一条流量为差值,费用为0的边,并弄一条流量为0且费用为0的反向边,然后相邻的两点连一条流量为inf,费用为1的边以及一条流量为0,费用为-1的反向边 2)直接求最小费用最大流即可

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<vector>
  6 #include<queue>
  7 using namespace std;
  8 //#define io_test
  9 #define debug(x) cout<<x<<"#######"<<dist[x]<<endl;
 10 typedef long long ll;
 11 ll a[105];
 12 const ll inf=0x3f3f3f3f;
 13 struct edge{
 14     int x;
 15     int y;
 16     ll v;
 17     ll c;
 18     int nex;
 19 }e[1005];
 20 ll flow,res;
 21 int cnt,head[505],n;
 22 void adde(int x1,int x2,ll v1,ll v2){
 23     e[cnt].c=v2;
 24     e[cnt].v=v1;
 25     e[cnt].x=x1;
 26     e[cnt].y=x2;
 27     e[cnt].nex=head[x1];
 28     head[x1]=cnt++;
 29 }
 30 int dist[505],prevv[505],preve[1005]; // 最短路的前驱节点 和 对应的边
 31 inline void min_cost_flow(int s,int t,int f)
 32 {
 33     while(f > 0)
 34     {
 35         memset(dist,inf,sizeof dist);
 36         dist[s] = 0;
 37         bool update = true;
 38         while(update)
 39         {
 40             update = false;
 41             for(int i=0;i<=n+1;i++)
 42             {
 43                 if(dist[i] == inf) continue;
 44                 for(int j=head[i];j!=-1; j=e[j].nex)
 45                 {
 46                     if(e[j].v > 0 && dist[e[j].y] > dist[i] + e[j].c)
 47                     {
 48                         dist[e[j].y] = dist[i] + e[j].c;
 49                         prevv[e[j].y] = i;
 50                         preve[e[j].y] = j;
 51                         update = true;
 52                     }
 53                 }
 54             }
 55         }
 56         // 此时的 INF 表示再也没有 增广路径,于是就是最后的答案了!
 57         if(dist[t] == inf) break;
 58         ll d = f;
 59         for(int v0 = t; v0 != s; v0 = prevv[v0])
 60             {d = min(d,e[preve[v0]].v);}
 61         // d 就是 增广路的 流量!
 62         f -= d;
 63         flow += d;
 64         res += d * dist[t];
 65         for(int v0=t;v0!=s;v0=prevv[v0])
 66         {
 67             e[preve[v0]].v -= d;
 68             e[preve[v0]^1].v += d; 
 69         }
 70     }
 71 }
 72 int main()
 73 {
 74 #ifdef io_test
 75     freopen("in.txt","r",stdin);
 76     freopen("out.txt","w",stdout);
 77 #endif // io_test
 78     scanf("%d",&n);
 79     ll sum=0;
 80     memset(head,-1,sizeof(head));
 81     for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum+=a[i];}
 82     for(int i=1;i<=n;i++){
 83         if(a[i]>sum/n){adde(0,i,a[i]-sum/n,0);adde(i,0,0,0);}
 84         if(a[i]<sum/n){adde(i,n+1,-a[i]+sum/n,0);adde(n+1,i,0,0);}
 85         if(i==n){
 86             adde(n,1,inf,1);
 87             adde(1,n,0,-1);
 88             adde(1,n,inf,1);
 89             adde(n,1,0,-1);
 90         }
 91         else{
 92             adde(i,(i+1),inf,1);
 93             adde(i+1,(i),0,-1);
 94             adde((i+1),i,inf,1);
 95             adde((i),i+1,0,-1);
 96         }
 97     }
 98     min_cost_flow(0,n+1,inf);
 99     printf("%lld\n",res);
100     return 0;
101 }
View Code

 

posted @ 2019-04-08 20:11  MekakuCityActor  阅读(162)  评论(0编辑  收藏  举报