洛谷P4016 负载平衡问题

洛谷P4016 负载平衡问题

题目大意:

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

能在相邻的仓库之间搬运。

思路:

  最小费用最大流。

  假设物品的总库存之和为sum,那么为了使库存之和相等,搬运结束后每一个仓库的目标库存量ave应该都等于sum/n。

  这时候很显然,我们发现初始库存量>ave的仓库会向其他仓库搬运货物,而初始库存量<ave的仓库会接收货物。

  所以我们将所有仓库的初始货物数nums[i]减去ave,如果nums[i]-ave>0,那么由超级源点向他发出一条流量为nums[i]-ave,费用为0的边。

  如果nums[i]-ave<0,那么由他向超级汇点发出一条流量为ave-nums[i],费用为0的边。

  最后再在所有相邻的仓库之间互相建立流量为无穷大,费用为1的双向边。

  然后就没有然后了。。。

我的错误o(╥﹏╥)o

  1、一开始直接跑了最大流,结果WA了9个点,后来发现最大流无法计算转移量之和,其实这是一个很蠢的错误、、、

  2、加双向边的时候有一个细节,因为我用的是邻接表,一开始加双向边的时候没有加入费用为负的辅助边,结果还是WA了9个点。。。

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <queue>
 6 using namespace std;
 7 #define MAXN 110
 8 struct Node{
 9     int u,v,w,c;
10     Node(){}
11     Node(int u,int v,int w,int c):u(u),v(v),w(w),c(c){}
12 }p[MAXN<<3];
13 struct Record{
14     int u,dis;
15     Record(){}
16     Record(int u,int dis):u(u),dis(dis){}
17     bool operator < (const Record & a) const{
18         return dis>a.dis;
19     }
20 };
21 int head[MAXN],Next[MAXN<<3],nums[MAXN],dis[MAXN],pre[MAXN],preNode[MAXN];
22 bool vis[MAXN];
23 int i,j,k,m,n,tot,sum;
24 void addNode(int u,int v,int w,int c){
25     p[++tot]=Node(u,v,w,c);
26     Next[tot]=head[u],head[u]=tot;
27     p[++tot]=Node(v,u,0,-c);
28     Next[tot]=head[v],head[v]=tot;
29 }
30 bool dijkstra(int src,int goal){
31     priority_queue<Record> mque;
32     while(!mque.empty()) mque.pop();
33     for(register int i=0;i<=n+1;i++) vis[i]=false,dis[i]=1000000000;
34     mque.push(Record(src,0));
35     vis[src]=true; dis[src]=0;
36     pre[src]=-1;
37     while(!mque.empty()){
38         Record tmp=mque.top(); mque.pop();
39         if(dis[tmp.u]<tmp.dis) continue;
40         //if(vis[tmp.u]) continue;
41         for(register int i=head[tmp.u];i+1;i=Next[i]){
42             if(p[i].w&&dis[tmp.u]+p[i].c<dis[p[i].v]){
43                 pre[p[i].v]=tmp.u;
44                 preNode[p[i].v]=i;
45                 dis[p[i].v]=dis[tmp.u]+p[i].c;
46                 mque.push(Record(p[i].v,dis[p[i].v]));
47             }
48         }
49     }
50     if(dis[goal]!=1000000000) return true;
51     return false;
52 }
53 int dinic(int src,int goal){
54     int ans=0;
55     while(dijkstra(src,goal)){
56         int minf=1000000000;
57         for(register int i=goal;i!=src;i=pre[i]){
58             minf=min(minf,p[preNode[i]].w);
59         }
60         for(register int i=goal;i!=src;i=pre[i]){
61             p[preNode[i]].w-=minf;
62             p[preNode[i]^1].w+=minf;
63         }
64         ans+=dis[goal]*minf;
65     }
66     return ans;
67 }
68 int main(){
69     scanf("%d",&n);
70     sum=0;
71     for(i=1;i<=n;i++) scanf("%d",nums+i),sum+=nums[i];
72     sum/=n;
73     for(i=0;i<=n+1;i++) head[i]=-1;
74     tot=-1;
75     for(i=1;i<=n;i++) nums[i]-=sum;
76     for(i=1;i<=n;i++) if(nums[i]>0) addNode(0,i,nums[i],0); else { if(nums[i]<0) addNode(i,n+1,-nums[i],0); }
77     for(i=1;i<=n-1;i++) addNode(i,i+1,10000000,1),addNode(i+1,i,10000000,1);
78     addNode(n,1,10000000,1),addNode(1,n,10000000,1);
79     printf("%d\n",dinic(0,n+1));
80     return 0;
81 }

 

转载于:https://www.cnblogs.com/linxif2008/p/9532392.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值