最大流
1. EK算法
这个算法效率谈不上多高,写上来主要是防止出现什么必须得用它的情况
//P3376#include <bits/stdc++.h>using namespace std;struct Edge {int from, to, flow;Edge(int u, int v, int f) : from(u), to(v), flow(f) {}};const int N = 210;int n, m, s, t;vector<Edge> edges;vector<int> G[N];int vis[N], inch[N], pre[N];long long maxflow;void addEdge(int from, int to, int flow) {edges.push_back((Edge){from, to, flow});G[from].push_back(edges.size() - 1);}bool bfs() {memset(vis, 0, sizeof(vis));queue<int> q;q.push(s), vis[s] = 1, inch[s] = 0x3f3f3f3f;while (!q.empty()) {int x = q.front(); q.pop();if (x == t) return true;for (int i = 0; i < G[x].size(); ++i) {Edge &e = edges[G[x][i]];int to = e.to;if (vis[to] || e.flow == 0)continue;inch[to] = min(inch[x], e.flow);pre[to] = G[x][i];q.push(to), vis[to] = 1;}}return false;}void update() {int x = t;while (x != s) {int i = pre[x];edges[ i ].flow -= inch[t];edges[i^1].flow += inch[t];x = edges[i].from;}maxflow += inch[t];}int main(){scanf("%d%d%d%d", &n, &m, &s, &t);for (int i = 1; i <= m; ++i) {int from, to, flow;scanf("%d%d%d", &from, &to, &flow);addEdge(from, to, flow);addEdge(to, from, 0);}while (bfs()) update();printf("%lld\n", maxflow);return 0;}
2. Dinic 算法
基于EK算法的优化,效率很高,基本上不太可能被卡。
#include<bits/stdc++.h>using namespace std;const int N = 210, M = 5010 * 2, INF = 1 << 30;int n, m, s, t;//int tot, head[N], Next[M], ver[M], Flow[M];void addEdge(int u, int v, int f) {ver[++tot] = v, Flow[tot] = f;Next[tot] = head[u], head[u] = tot;}//int d[N];queue<int> q;bool bfs(){memset(d, 0, sizeof(d));while (!q.empty()) q.pop();q.push(s), d[s] = 1;while (!q.empty()) {int x = q.front(); q.pop();if (x == t) return true;for (int i = head[x]; i; i = Next[i]) {int to = ver[i];if (!d[to] && Flow[i])q.push(to), d[to] = d[x] + 1;}}return false;}//int Dinic(int x, int flow) {if (x == t) return flow;int rest = flow;for (int i = head[x]; i; i = Next[i]) {int to = ver[i];if (Flow[i] && d[to] == d[x] + 1) {int k = Dinic(to, min(rest, Flow[i]));if (!k) d[to] = 0;Flow[i] -= k, Flow[i^1] += k;rest -= k;if (rest == 0) break;}}if (rest == flow) d[x] = 0;return flow - rest;}int main(){//inputscanf("%d%d%d%d", &n, &m, &s, &t);tot = -1;for (int i = 1; i <= m; ++i) {int from, to, flow;scanf("%d%d%d", &from, &to, &flow);addEdge(from, to, flow);addEdge(to, from, 0 );}//solvelong long maxflow = 0;int flow;while (bfs())while (flow = Dinic(s, INF)) maxflow += flow;//outputprintf("%lld\n", maxflow);return 0;}
费用流
最小费用最大流
和 EK 算法类似,不过把增广路的 BFS 换成了 SPFA
#include<bits/stdc++.h>using namespace std;#define LL long longconst int N = 5010, M = 100010;const LL INF = 0x3f3f3f3f3f3f3f3f;int n, m, s, t;LL maxflow, ans;int tot, Head[N], Next[M], ver[M];LL Flow[M], Cost[M];void addEdge(int u, int v, LL flow, LL cost) {ver[++tot] = v, Flow[tot] = flow, Cost[tot] = cost;Next[tot] = Head[u], Head[u] = tot;}LL d[N], incf[N];int pre[N], vis[N];bool SPFA() {queue<int> q;memset(d, 0x3f, sizeof(d));memset(vis, 0, sizeof(vis));q.push(s), d[s] = 0, vis[s] = 1;incf[s] = INF;while (!q.empty()) {int x = q.front(); q.pop();vis[x] = 0;for (int i = Head[x]; i; i = Next[i]) {if (!Flow[i]) continue;int to = ver[i];if (d[to] > d[x] + Cost[i]) {d[to] = d[x] + Cost[i];incf[to] = min(incf[x], Flow[i]);pre[to] = i;if (!vis[to]) vis[to] = 1, q.push(to);}}}return (d[t] != INF);}void update() {int x = t;while (x != s) {int i = pre[x];Flow[i] -= incf[t], Flow[i^1] += incf[t];x = ver[i^1];}maxflow += incf[t];ans += d[t] * incf[t];}int main(){scanf("%d%d%d%d", &n, &m, &s, &t);tot = 1;for (int i = 1; i <= m; ++i) {int u, v;LL flow, cost;scanf("%d%d%lld%lld", &u, &v, &flow, &cost);addEdge(u, v, flow, cost);addEdge(v, u, 0 , -cost);}while (SPFA()) update();printf("%lld %lld", maxflow, ans);return 0;}
最大费用最大流
将费用取反后放进图里跑,得到的结果的相反数就是答案。
