[网络流24题] 负载平衡问题 (费用流)
本题解思路来自hzwer黄学长
搬运后每个位置应该有的货物数量$num=\frac{\sum a_{i}}{n}$
那么大于$num$的位置都应该把一部分货物提供给其他位置,反之是被提供货物
把源点和汇点想象成货物中心
那么源点向$a_{i}>num$的位置连一条流量为$a_{i}-num$,长度是$0$的边
向$a_{i}<num$的位置向汇点连一条流量为$num-a_{i}$,长度是$0$的边
而相邻的货物间可以随便运货,故连一条流量是$inf$,长度是$1$的边,注意货物的是一个环
源点向汇点的一条可行流可以理解成,连接源点的那个点 贡献出$flow$数量的货物,长途跋涉,到达连接汇点的那个点
我们的目的是保证每个位置多出来的货物全部运给少的,而这个图的最大流其实就是把连接源点的边全都跑满
我们要求的是最少花费,跑最小费用最大流就行了
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 105 6 #define M1 50010 7 #define ll long long 8 #define dd double 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 12 int gint() 13 { 14 int ret=0,fh=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 16 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 17 return ret*fh; 18 } 19 20 int n,m,S,T; 21 struct Edge{ 22 int head[N1],to[M1<<1],nxt[M1<<1],dis[M1<<1],flow[M1<<1],cte; 23 void ae(int u,int v,int F,int W) 24 { 25 cte++; to[cte]=v; flow[cte]=F; dis[cte]=W; 26 nxt[cte]=head[u]; head[u]=cte; 27 } 28 }e; 29 30 int que[M1<<1],dis[N1],flow[N1],use[N1],id[N1],hd,tl; 31 int spfa() 32 { 33 int x,j,v; 34 memset(dis,0x3f,sizeof(dis)); memset(use,0,sizeof(use)); memset(flow,0,sizeof(flow)); 35 hd=1,tl=0; que[++tl]=S; dis[S]=0; flow[S]=inf; use[S]=1; 36 while(hd<=tl) 37 { 38 x=que[hd++]; 39 for(j=e.head[x];j;j=e.nxt[j]) 40 { 41 v=e.to[j]; 42 if( e.flow[j]>0 && dis[v]>dis[x]+e.dis[j] ) 43 { 44 dis[v]=dis[x]+e.dis[j]; id[v]=j; 45 flow[v]=min(flow[x],e.flow[j]); 46 if(!use[v]) que[++tl]=v, use[v]=1; 47 } 48 } 49 use[x]=0; 50 } 51 return dis[T]!=inf; 52 } 53 54 int mxflow,cost; 55 int EK() 56 { 57 int x; 58 while(spfa()) 59 { 60 for(x=T;x!=S;x=e.to[id[x]^1]) 61 { 62 e.flow[id[x]]-=flow[T]; 63 e.flow[id[x]^1]+=flow[T]; 64 } 65 mxflow+=flow[T]; cost+=flow[T]*dis[T]; 66 } 67 return cost; 68 } 69 70 int a[N1]; 71 72 int main() 73 { 74 scanf("%d",&n); 75 int i,x,y,z,sum=0; e.cte=1; S=n+1,T=n+2; 76 for(i=1;i<=n;i++) scanf("%d",&a[i]), sum+=a[i]; sum/=n; 77 for(i=1;i<=n;i++) 78 if(a[i]>sum) e.ae(S,i,a[i]-sum,0), e.ae(i,S,0,0); 79 else if(a[i]<sum) e.ae(i,T,sum-a[i],0), e.ae(T,i,0,0); 80 for(i=1;i<n;i++) e.ae(i,i+1,inf,1), e.ae(i+1,i,0,-1); e.ae(n,1,inf,1), e.ae(1,n,0,-1); 81 for(i=2;i<=n;i++) e.ae(i,i-1,inf,1), e.ae(i-1,i,0,-1); e.ae(1,n,inf,1), e.ae(n,1,0,-1); 82 printf("%d\n",EK()); 83 //for(i=1,num=0;i<=n;i++) num+=abs(a[i]-sum); 84 return 0; 85 }