bzoj [ZJOI2010]网络扩容 - 费用流

1834: [ZJOI2010]network 网络扩容

Time Limit: 3 Sec  Memory Limit: 64 MB

Description

给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。
求: 
1、在不扩容的情况下,1到N的最大流; 
2、将1到N的最大流增加K所需的最小扩容费用。

Input

第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 
接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。
N<=1000,M<=5000,K<=10

Output

输出文件一行包含两个整数,分别表示问题1和问题2的答案。

Sample Input

5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1

Sample Output

13 19
 
先跑出最大流,然后在残量网络上加边,每条边的费用为 c, 限制 n 到汇点的流量为k
跑费用流,流量流过一次就代表要进行扩容
跑出的费用就是答案
 
 
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #define LL long long
  7 
  8 using namespace std;
  9 
 10 const int MAXM = 1e5 + 10;
 11 const int MAXN = 2e3 + 10;
 12 
 13 queue<int> q;
 14 int S, T;
 15 int N, M, K;
 16 LL u, v, c, w;
 17 const LL inf = 1e9;
 18 LL maxflow = 0;
 19 LL sum = 0;
 20 int cnt = 0;
 21 int pre[MAXN];
 22 int flag[MAXN];
 23 int dis[MAXN];
 24 int e[MAXN];
 25 int h[MAXN];
 26 int head[MAXN];
 27 struct edge {
 28     int u, v;
 29     LL w;
 30     LL c;
 31     int next;
 32 } g[5 * MAXM], ed[2 * MAXM];
 33 
 34 inline LL read()
 35 {
 36     LL x = 0, w = 1; char ch = 0;
 37     while(ch < '0' || ch > '9') {
 38         if(ch == '-') {
 39             w = -1;
 40         }
 41         ch = getchar();
 42     }
 43     while(ch >= '0' && ch <= '9') {
 44         x = x * 10 + ch - '0';
 45         ch = getchar();    
 46     }
 47     return x * w;
 48 }
 49 
 50 void addedge(int u, int v, LL w, LL c)
 51 {
 52     g[cnt].v = v;
 53     g[cnt].w = w;
 54     g[cnt].c = c;
 55     g[cnt].next = head[u];
 56     head[u] = cnt++;
 57 }
 58 
 59 bool BFS() 
 60 {
 61     memset(h, -1, sizeof h);
 62     h[S] = 0;
 63     q.push(S);
 64     while(!q.empty()) {
 65         int t = q.front();
 66         q.pop();
 67         for(int j = head[t]; j != -1; j = g[j].next) {
 68             int to = g[j].v;
 69             if(h[to] == -1 && g[j].w) {
 70                 h[to] = h[t] + 1;
 71                 q.push(to);
 72             }
 73         }
 74     }
 75     return h[T] != -1;
 76 }
 77 
 78 LL DFS(int x, LL f)
 79 {
 80     LL used = 0;
 81     if(x == T) {
 82         return f;
 83     }
 84     for(int j = head[x]; j != -1; j = g[j].next) {
 85         int to = g[j].v;
 86         if(h[to] == h[x] + 1 && g[j].w) {
 87             LL w = f - used;
 88             w = DFS(to, min(w, g[j].w));
 89             g[j].w -= w, g[j ^ 1].w += w;
 90             used += w;
 91             if(used == f) {
 92                 break;
 93             }
 94         }
 95     }
 96     if(used == 0) {
 97         h[x] = -1;
 98     }
 99     return used;
100 }
101 
102 void dinic()
103 {
104     while(BFS()) {
105         maxflow += DFS(S, inf);
106     }
107 }
108 
109 bool SPFA()
110 {
111     memset(pre, -1, sizeof pre);
112     memset(flag, 0, sizeof flag);
113     memset(dis, -1, sizeof dis);
114     dis[S] = 0;
115     q.push(S);
116     while(!q.empty()) {
117         int t = q.front();
118         q.pop();
119         flag[t] = 0;
120         for(int j = head[t]; j != -1; j = g[j].next) {
121             int to = g[j].v;
122             if(g[j].w && (dis[to] == -1 || dis[to] > (dis[t] + g[j].c))) {
123                 dis[to] = dis[t] + g[j].c;
124                 e[to] = j;
125                 pre[to] = t;
126                 if(!flag[to]) {
127                     flag[to] = 1;
128                     q.push(to);
129                 }
130             }
131         }
132     }
133     if(pre[T] == -1) {
134         return false;
135     }
136     LL maxflow = 1e18;
137     for(int j = T; pre[j] != -1; j = pre[j]) {
138         maxflow = min(g[e[j]].w, maxflow);
139     }
140     for(int j = T; pre[j] != -1; j = pre[j]) {
141         g[e[j]].w -= maxflow, g[e[j] ^ 1].w += maxflow;
142     }
143     sum += maxflow * dis[T];
144 }
145 
146 int main()
147 {
148     memset(head, -1, sizeof head);
149     N = read(), M = read(), K = read();
150     S = 0, T = N + 1;
151     for(int i = 1; i <= M; i++) {
152         u = read(), v = read(), w = read(), c = read();
153         addedge(u, v, w, 0);
154         addedge(v, u, 0, 0);
155         ed[i].u = u, ed[i].v = v, ed[i].w = w, ed[i].c = c;
156     }
157     addedge(S, 1, inf, 0);
158     addedge(1, S, 0, 0);
159     addedge(N, T, inf, 0);
160     addedge(T, N, 0, 0);
161     dinic();
162     printf("%lld ", maxflow);
163     for(int i = 1; i <= M; i++) {
164         addedge(ed[i].u, ed[i].v, K, ed[i].c);
165         addedge(ed[i].v, ed[i].u, 0, -ed[i].c);
166     } 
167     g[2 * M].w = K;
168     g[2 * M + 1].w = 0;
169     while(SPFA()) {
170     }
171     printf("%lld\n", sum);
172     return 0;
173 }
174 
175 
176 /*
177 5 8 2
178 1 2 5 8
179 2 5 9 9
180 5 1 6 2
181 5 1 1 8
182 1 2 8 7
183 2 5 4 9
184 1 2 1 1
185 1 4 2 1
186 
187 */
View Code

 

 

转载于:https://www.cnblogs.com/wuenze/p/8638905.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值