您的位置:首页 > 理论基础 > 计算机网络

[BZOJ1834][ZJOI2010]网络扩容(最大流+费用流)

2018-01-01 19:40 501 查看
第一问即为模板最大流。

第二问在跑完最大流的残余网络上继续建图,对于没有满流的边,将其费用置为0。同时对于所有的边<u,v>,再建一条边<u,v>,容量为∞,费用为边<u,v>的扩容费用。

同时,还需要建一个新的源点连向原图中的源点,容量为K,费用为0。

这样,最小的扩容费用就是最小费用最大流。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5, INF = 0x3f3f3f3f;
int n, m, ecnt = 1, nxt
, adj
, go
, cap
, dis
, lev
,
yd = 1, hd, len, que
, cost
, Ans, K, Y
, st
, Cap
;
bool vis
, walk
;
void add_edge(int u, int v, int w, int x) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
cap[ecnt] = w; cost[ecnt] = x; st[ecnt] = u;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
cap[ecnt] = 0; cost[ecnt] = -x; st[ecnt] = v;
}
bool bfs() {
int i; for (i = yd; i <= hd; i++) lev[i] = -1;
que[len = 1] = yd; lev[yd] = 0;
for (i = 1; i <= len; i++) {
int u = que[i];
for (int e = adj[u], v; e; e = nxt[e])
if (cap[e] > 0 && lev[v = go[e]] == -1) {
lev[v] = lev[u] + 1; que[++len] = v;
if (v == hd) return 1;
}
}
return 0;
}
int dinic(int u, int flow) {
if (u == hd) return flow;
int res = 0, d;
for (int e = adj[u], v; e; e = nxt[e])
if (cap[e] > 0 && lev[u] < lev[v = go[e]]) {
d = dinic(v, min(cap[e], flow - res));
if (d) {
cap[e] -= d; cap[e ^ 1] += d;
res += d; if (res == flow) break;
}
}
if (res != flow) lev[u] = -1;
return res;
}
int solve() {
int ans = 0; while (bfs()) ans += dinic(yd, INF); return ans;
}
bool bfs2() {
que[len = 1] = yd; int i;
for (i = 1; i <= yd; i++) dis[i] = INF, walk[i] = 0;
vis[yd] = 1; dis[yd] = 0;
for (i = 1; i <= len; i++) {
int u; vis[u = que[i]] = 0;
for (int e = adj[u], v; e; e = nxt[e])
if (cap[e] > 0 && dis[u] + cost[e] < dis[v = go[e]]) {
dis[v] = dis[u] + cost[e];
if (!vis[v]) vis[v] = 1, que[++len] = v;
}
}
return dis[hd] < INF;
}
int dinic2(int u, int flow) {
if (u == hd) return Ans += flow * dis[hd], flow;
walk[u] = 1; int res = 0, delta = 0;
for (int e = adj[u], v; e; e = nxt[e])
if (cap[e] > 0 && !walk[v = go[e]]
&& dis[u] + cost[e] == dis[v]) {
delta = dinic2(v, min(cap[e], flow - res));
if (delta) {
cap[e] -= delta; cap[e ^ 1] += delta;
res += delta; if (res == flow) break;
}
}
return res;
}
int solve2() {
Ans = 0; while (bfs2()) dinic2(yd, INF); return Ans;
}
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
int main() {
int i, u, v, x, y, ff; n = hd = read(); m = read(); K = read();
for (i = 1; i <= m; i++) u = read(), v = read(), x = read(),
y = read(), add_edge(u, v, x, y), Cap[ecnt - 1] = x;
printf("%d ", solve()); ff = ecnt;
for (i = 2; i <= ff; i += 2) {
if (cap[i] > 0) add_edge(st[i], go[i], cap[i], 0),
cap[ecnt] = cap[i ^ 1]; cap[i] = INF; cap[i ^ 1] = 0;
}
yd = hd + 1; add_edge(yd, 1, K, 0); printf("%d\n", solve2());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: