这篇博客这是记录网络流板子的,不进行网络流的讲解。用注释标注了一些易错或重要步骤。 Dinic(无当前弧优化) dinic 的当前弧优化其实快不了多少,而且容易出事。 完整代码 cpp复制代码#include <bits/stdc++.h> using namespace std; const int maxM = 1e5 + 3; const int maxN = 1e4 + 3; const int INF = 0x3f3f3f3f; struct Edge { int next, to, cap; } edge[maxM << 1]; int head[maxN], lvl[maxN]; int n, m, cnt = -1, s, t; // cnt 需要初始化为奇数,因为需要用异或(^)表示反向边 void add(int from, int to, int cost) { edge[++cnt] = (Edge) {head[from], to, cost}; head[from] = cnt; } void addEdge(int from, int to, int cost) { add(from, to, cost); add(to, from, 0); } queue<int> que; bool bfs() { // BFS 标号过程 memset(lvl, -1, sizeof(lvl)); lvl[s] = 0; que.push(s); while (!que.empty()) { int u = que.front(); que.pop(); for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if (lvl[v] < 0 && edge[i].cap) { lvl[v] = lvl[u] + 1; que.push(v); } } } return lvl[t] != -1; } int dfs(int u, int f) { if (!f || u == t) return f; int flow = 0; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if (lvl[v] == lvl[u] + 1 && edge[i].cap) { int d = dfs(v, min(f, edge[i].cap)); flow += d; f -= d; edge[i].cap -= d; edge[i ^ 1].cap += d; } } if (!flow) lvl[u] = -1; return flow; } int dinic() { int ans = 0; while (bfs()) ans += dfs(s, INF); return ans; } int main() { memset(head, -1, sizeof(head)); scanf("%d%d%d%d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); addEdge(a, b, c); } printf("%d\n", dinic()); return 0; } 最小费用最大流(SPFA 版) 就是把 dinic 算法中 BFS 标号过程魔改成了 SPFA,求最大流是根据进行 SPFA 所记录的路径进行的。 完整代码 cpp复制代码#include <bits/stdc++.h> using namespace std; const int maxM = 5e4 + 3, maxN = 5e3 + 3; const int INF = 0x7f7f7f7f; struct Edge { int next, to, cap, cost; } edge[maxM << 1]; int head[maxN], dis[maxN], pre[maxN], preEdge[maxN]; bool vis[maxN]; int s, t, n, m, cnt = -1, minCost, maxFlow; void add(int from, int to, int val, int cost) { edge[++cnt] = (Edge) {head[from], to, val, cost}; head[from] = cnt; } void addEdge(int from, int to, int val, int cost) { add(from, to, val, cost); add(to, from, 0, -cost); } queue<int> que; bool spfa() { memset(dis, 0x7f, sizeof(dis)); memset(vis, false, sizeof(vis)); dis[s] = 0; vis[s] = true; que.push(s); while (!que.empty()) { int u = que.front(); que.pop(); vis[u] = false; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if (dis[v] > dis[u] + edge[i].cost && edge[i].cap) { dis[v] = dis[u] + edge[i].cost; pre[v] = u; // 用于记录路径,记录当前点所连的前一个点 preEdge[v] = i; // 记录路径,记录当前点所连的前一条边 if (!vis[v]) { que.push(v); vis[v] = true; } } } } return dis[t] != INF; } void work() { while (spfa()) { int flow = INF; for (int i = t; i != s; i = pre[i]) flow = min(flow, edge[preEdge[i]].cap); maxFlow += flow; minCost += dis[t] * flow; for (int i = t; i != s; i = pre[i]) { edge[preEdge[i]].cap -= flow; edge[preEdge[i] ^ 1].cap += flow; } } } int main() { memset(head, -1, sizeof(head)); scanf("%d%d%d%d", &n, &m, &s, &t); for (int i = 1; i <= m; i++) { int a, b, x, y; scanf("%d%d%d%d", &a, &b, &x, &y); addEdge(a, b, x, y); } work(); printf("%d\n", minCost); return 0; }