int n, m, s, t, u, v, f; int head[N], idx = 1; structNode { int nxt, to; LL f; }edge[M << 1]; // graph int pre[N], pos[N][N]; // pre 用于存储增广路中一点的前驱, 用于寻找增广路 // pos 作为重边优化存储链表位置 LL incf[N], maxFlow; bool vis[N];
寻找增广路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
boolbfs(){ for (int i = 1; i <= n; ++ i) vis[i] = false; queue<int> q; q.push(s), vis[s] = true, incf[s] = INF; while (q.size()) { auto u = q.front(); q.pop(); for (int i = head[u], j; ~i; i = edge[i].nxt) { if (!edge[i].f) continue; j = edge[i].to; if (vis[j]) continue; incf[j] = min(incf[u], edge[i].f); pre[j] = i; // 记录当前点前驱, 用于倒推增广路, 注意存储的是 nxt 指针 q.push(j), vis[j] = true; if (j == t) returntrue; } } returnfalse; }
使用 $bfs$ 搜到的增广路更新剩余流量与答案 $maxFlow$
增广路可行流 $f$ 为增广路中所有边剩余流量最小值, 即为 $incf_t$
1 2 3 4 5 6 7 8 9 10
voidupdate(){ int x = t, i; while (x != s) { i = pre[x]; edge[i].f -= incf[t]; edge[i ^ 1].f += incf[t]; // 修改反向边剩余流量 x = edge[i ^ 1].to; } maxFlow += incf[t]; }
注意连入反向边, 并将反向边限制流量设为 $0$.
1 2 3 4 5 6 7 8 9 10 11 12 13
intmain(){ input(n), input(m), input(s), input(t); memset(head, -1, sizeof(int) * (n + 10)); for (int i = 1; i <= m; ++ i) { input(u), input(v), input(f); if (pos[u][v]) edge[pos[u][v]].f += f; elseadd(u, v, f), pos[u][v] = idx, add(v, u, 0); // 重边优化 } while (bfs()) update(); cout << maxFlow << endl; return0; }
int n, m, s, t, u, v, f, maxFlow; int head[N], now[N], idx = 1; structNode { int nxt, to, f; } edge[M << 1]; // graph int dis[N], pos[N][N]; // pos 用于重边优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
boolbfs(){ for (int i = 1; i <= n; ++ i) dis[i] = INF; queue<int> q; q.push(s), dis[s] = 0, now[s] = head[s]; while (q.size()) { int u = q.front(); q.pop(); for (int i = head[u], j; ~i; i = edge[i].nxt) { if (edge[i].f and dis[j = edge[i].to] == INF) { q.push(j), dis[j] = dis[u] + 1, now[j] = head[j]; if (j == t) returntrue; } } } returnfalse; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intdfs(int u, int limit){ if (u == t) return limit; int k, res = limit; for (int i = now[u], j; ~i and res; i = edge[i].nxt) { now[u] = i, j = edge[i].to; if (edge[i].f and dis[j] == dis[u] + 1) { k = dfs(j, min(res, edge[i].f)); if (!k) dis[j] = INF; edge[i].f -= k; edge[i ^ 1].f += k; res -= k; } } return limit - res; }
1 2 3 4 5 6 7 8 9 10 11 12
intmain(){ input(n), input(m), input(s), input(t); memset(head, -1, sizeof(int) * (n + 10)); for (int i = 1; i <= m; ++ i) { input(u), input(v), input(f); if (pos[u][v]) edge[pos[u][v]].f += f; elseadd(u, v, f), pos[u][v] = idx, add(v, u, 0); } while (bfs()) maxFlow += dfs(s, INF); cout << maxFlow << endl; return0; }
int n, m, s, t, u, v, f, c, maxFlow, minCost; // bases int head[N], now[N], idx = 1; structNode { int nxt, to, f, c; }edge[M << 1]; // graph int dis[N]; bool st[N]; // spfa
找到费用最小的增广路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
boolspfa(){ memset(st, 0, sizeof st); for (int i = 1; i <= n; ++ i) dis[i] = 0x3f3f3f3f; queue<int> q; q.push(s), dis[s] = 0, st[s] = true, now[s] = head[s]; while (q.size()) { int u = q.front(); q.pop(); st[u] = false; for (int i = head[u], j; ~i; i = edge[i].nxt) { j = edge[i].to; if (edge[i].f and dis[j] > dis[u] + edge[i].c) { dis[j] = dis[u] + edge[i].c; now[j] = head[j]; if (!st[j]) q.push(j), st[j] = true; } } } return dis[t] != INF; }
更新增广路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
intdfs(int u, int limit){ if (u == t) return limit; int k, res = limit; st[u] = true; for (int i = now[u], j; ~i and res; i = edge[i].nxt) { now[u] = i; j = edge[i].to; if (!st[j] and edge[i].f and dis[j] == dis[u] + edge[i].c) { k = dfs(j, min(res, edge[i].f)); if (!k) dis[j] = INF; edge[i].f -= k; edge[i ^ 1].f += k; res -= k; minCost += edge[i].c * k; } } st[u] = false; return limit - res; }
建图及统计答案
1 2 3 4 5 6 7 8 9 10 11
intmain(){ memset(head, -1, sizeof head); input(n), input(m), input(s), input(t); for (int i = 1; i <= m; ++ i) { input(u), input(v), input(f), input(c); add(u, v, f, c), add(v, u, 0, -c); } while (spfa()) maxFlow += dfs(s, INF); cout << maxFlow << ' ' << minCost << endl; return0; }