LuoguP4016 负载平衡问题(费用流)
题目描述
G 公司有 n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等。如何用最少搬运量可以使 n 个仓库的库存数量相同。搬运货物时,只能在相邻的仓库之间搬运。
输入输出格式
输入格式:
文件的第 11 行中有 11 个正整数 n,表示有 n 个仓库。
第 22 行中有 n 个正整数,表示 n 个仓库的库存量。
输出格式:
输出最少搬运量。
解题思路:
因为已知了最终状态,相当于已知每个点的搬运数量。
现在就是令搬运次数尽量少。
相当于每个点与相邻点连inf的边费用为1
大于平均值与汇点连流量为增量边费用为0
源点与小于平均值连流量为增量边费用为0
跑费用流就好了。
代码:
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 const int oo=0x7f7f7f7f; 6 struct pnt{ 7 int hd; 8 int val; 9 int dis; 10 int pre; 11 int lst; 12 bool vis; 13 }p[1001]; 14 struct ent{ 15 int twd; 16 int lst; 17 int vls; 18 int cst; 19 }e[100000]; 20 int cnt; 21 int n,m; 22 int s,t; 23 int a[10000]; 24 std::queue<int>Q; 25 void ade(int f,int t,int mf,int ct) 26 { 27 cnt++; 28 e[cnt].twd=t; 29 e[cnt].lst=p[f].hd; 30 e[cnt].vls=mf; 31 e[cnt].cst=ct; 32 p[f].hd=cnt; 33 return ; 34 } 35 bool Spfa(void) 36 { 37 while(!Q.empty()) 38 Q.pop(); 39 for(int i=1;i<=n+2;i++) 40 { 41 p[i].val=0x3f3f3f3f; 42 p[i].dis=0x3f3f3f3f; 43 p[i].vis=false; 44 } 45 p[s].dis=0; 46 p[s].vis=true; 47 p[t].pre=-1; 48 Q.push(s); 49 while(!Q.empty()) 50 { 51 int x=Q.front(); 52 Q.pop(); 53 p[x].vis=false; 54 for(int i=p[x].hd;i;i=e[i].lst) 55 { 56 int to=e[i].twd; 57 if(e[i].vls>0&&p[to].dis>p[x].dis+e[i].cst) 58 { 59 p[to].dis=p[x].dis+e[i].cst; 60 p[to].val=std::min(p[x].val,e[i].vls); 61 p[to].pre=x; 62 p[to].lst=i; 63 if(!p[to].vis) 64 { 65 p[to].vis=true; 66 Q.push(to); 67 } 68 } 69 } 70 } 71 return p[t].pre!=-1; 72 } 73 int Ek(void) 74 { 75 int ret=0; 76 while(Spfa()) 77 { 78 ret+=p[t].dis*p[t].val; 79 for(int i=t;i!=s;i=p[i].pre) 80 { 81 e[p[i].lst].vls-=p[t].val; 82 e[((p[i].lst-1)^1)+1].vls+=p[t].val; 83 } 84 } 85 return ret; 86 } 87 int main() 88 { 89 // freopen("a.in","r",stdin); 90 int sum=0; 91 scanf("%d",&n); 92 for(int i=1;i<=n;i++) 93 { 94 scanf("%d",&a[i]); 95 sum+=a[i]; 96 } 97 s=n+1,t=n+2; 98 sum/=n; 99 for(int i=1;i<=n;i++) 100 { 101 if(a[i]>sum) 102 { 103 ade(s,i,a[i]-sum,0); 104 ade(i,s,0,0); 105 }else{ 106 ade(i,t,sum-a[i],0); 107 ade(t,i,0,0); 108 } 109 } 110 for(int i=1;i<n;i++) 111 { 112 ade(i,i+1,oo,1);ade(i+1,i,0,-1); 113 ade(i+1,i,oo,1);ade(i,i+1,0,-1); 114 } 115 ade(1,n,oo,1);ade(n,1,0,-1); 116 ade(n,1,oo,1);ade(1,n,0,-1); 117 printf("%d\n",Ek()); 118 return 0; 119 }