最大流模板
Posted 我不吃饼干呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最大流模板相关的知识,希望对你有一定的参考价值。
最简单的Ford-Fulkerson,复杂度O(FE) (F是最大流量,E是边数
每次从源点到汇点dfs寻找增广路。
const int MAXV = 2005; const int INF = 1<<30; struct Edge{ int to, cap, rev; }; std::vector<Edge> G[MAXV]; bool used[MAXV]; void addedge(int from, int to, int cap) { G[from].push_back(Edge{to, cap, G[to].size()}); G[to].push_back(Edge{from, 0, G[from].size()-1}); } int dfs(int v, int t, int f) { if (v == t) return f; used[v] = true; for (int i = 0; i < G[v].size(); ++i) { Edge &e = G[v][i]; if (!used[e.to] && e.cap > 0) { int d = dfs(e.to, t, std::min(f, e.cap)); if (d > 0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } int maxflow(int s, int t) { int flow = 0; for (; ;) { memset(used, 0, sizeof used); int f = dfs(s, t, INF); if (!f) return flow; flow += f; } return flow; }
把dfs换成bfs,就成了Edmonds-Karp
代码多了一些,但是并不会快的样子。。
#include <queue> #include <cstring> const int N = 2005; const int M = 2005; const int INF = 0x7fffffff; struct Edge { int from, to, next, cost; } edge[M]; int head[N]; int cnt_edge; void add_edge(int u, int v, int c) { edge[cnt_edge].to = v; edge[cnt_edge].from = u; edge[cnt_edge].cost = c; edge[cnt_edge].next = head[u]; head[u] = cnt_edge++; } int pre[N], flow[N]; std::queue<int> q; int bfs(int src, int des) { memset(pre, -1, sizeof pre); while (!q.empty()) q.pop(); q.push(src); flow[src] = INF; while (!q.empty()) { int u = q.front(); q.pop(); if (u == des) break; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; int cost = edge[i].cost; if (pre[v] == -1 && cost > 0) { flow[v] = std::min(flow[u], cost); pre[v] = i; // 记录的是边 q.push(v); } } } if (pre[des] == -1) return -1; return flow[des]; } int maxFlow(int src, int des) { int ans = 0; int in; while ((in = bfs(src, des)) != -1) { int k = des; while (k != src) { int last = pre[k]; edge[last].cost -= in; edge[last ^ 1].cost += in; k = edge[last].from; } ans += in; } return ans; } int main() { int n, m; while (~scanf("%d%d", &m, &n)) { int a, b, c; memset(head, -1, sizeof head); while (m--) { scanf("%d%d%d", &a, &b, &c); add_edge(a, b, c); add_edge(b, a, 0); } printf("%d\\n", maxFlow(1, n)); } }
优化下,bfs构造分层图,然后每次都走最短的增广路,变成Dinic
这样比上面快很多。。复杂度O(EV²) (E是边数,V是点数
有了大概这个可以放弃上面的两个了。。
据说比较适合有向无环图。。
#include <cstdio> #include <vector> #include <cstring> #include <queue> const int MAXV = 2005; const int INF = 1<<30; struct Edge{ int to, cap, rev; }; std::vector<Edge> G[MAXV]; int level[MAXV]; int iter[MAXV]; //当前弧,之前的已经没有用了 void addedge(int from, int to, int cap) { G[from].push_back(Edge{to, cap, G[to].size()}); G[to].push_back(Edge{from, 0, G[from].size()-1}); } void bfs(int s) { memset(level, -1, sizeof level); std::queue<int> que; level[s] = 0; que.push(s); while (!que.empty()) { int v = que.front(); que.pop(); for (int i = 0; i < G[v].size(); ++i) { Edge &e = G[v][i]; if (e.cap > 0 && level[e.to] < 0) { level[e.to] = level[v] + 1; que.push(e.to); } } } } int dfs(int v, int t, int f) { if (v == t) return f; for (int &i = iter[v]; i < G[v].size(); ++i) { // 注意i是引用 实现当前弧优化 Edge &e = G[v][i]; if (e.cap > 0 && level[v] < level[e.to]) { int d = dfs(e.to, t, std::min(f, e.cap)); if (d > 0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } int maxflow(int s, int t) { int flow = 0; for (; ;) { bfs(s); if (level[t] < 0) return flow; memset(iter, 0, sizeof iter); int f; while ((f = dfs(s, t, INF)) > 0) { flow += f; } } return flow; }
SAP。。。并不是很懂。。。
貌似没有比dinic快很多。。。
const int N = 1000; const int M = 1000000; const int INF = 1 << 30; struct Edge { int from, to, next, w;//from一般用不到 } edge[M]; int head[N], cntE; int src, sink; int pre[N], cur[N], dis[N], gap[N]; int que[N], open, tail; void addedge(int u, int v, int w) { edge[cntE].from = u; edge[cntE].to = v; edge[cntE].w = w; edge[cntE].next = head[u]; head[u] = cntE++; edge[cntE].from = v; edge[cntE].to = u; edge[cntE].w = 0; edge[cntE].next = head[v]; head[v] = cntE++; } void BFS() { int i, u, v; memset(gap, 0, sizeof(gap)); memset(dis, -1, sizeof(dis)); open = tail = 0; que[open] = sink; dis[sink] = 0; while (open <= tail) { u = que[open++]; for (i = head[u]; ~i; i = edge[i].next) { v = edge[i].to; if (edge[i].w != 0 || dis[v] != -1) continue; que[++tail] = v; ++gap[dis[v] = dis[u] + 1]; } } } int sap(int n) { //编号从1开始 1~n int i, v, u, flow = 0, aug = INF; int flag; BFS(); gap[0] = 1; for (i = 1; i <= n; i++) cur[i] = head[i]; u = pre[src] = src; while (dis[src] < n) { flag = 0; for (int j = cur[u]; ~j; j = edge[j].next) { v = edge[j].to; if (edge[j].w > 0 && dis[u] == dis[v] + 1) { flag = 1; if (edge[j].w < aug) aug = edge[j].w; pre[v] = u; u = v; if (u == sink) { flow += aug; while (u != src) { u = pre[u]; edge[cur[u]].w -= aug; edge[cur[u] ^ 1].w += aug; } aug = INF; } break; } cur[u] = edge[j].next; } if (flag) continue; int mindis = n; for (int j = head[u]; ~j; j = edge[j].next) { v = edge[j].to; if (edge[j].w > 0 && mindis > dis[v]) { mindis = dis[v]; cur[u] = j; } } if (--gap[dis[u]] == 0) break; ++gap[dis[u] = mindis + 1]; u = pre[u]; } return flow; } int main() { memset(head, -1, sizeof head); cntE = 0; }
我决定选择dinic吧。。。好写。。。Orz。。
最小费用最大流。。每次spfa找最短路增广。。
好像挺慢的。。。
#include <cstring> #include <cstdio> #include <queue> #define CLR(x, v, n) memset(x, v, sizeof(x[0])*n) using namespace std; const int N = 10000; const int M = 1000000; const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow, cost; void init(int _to, int _cap, int _cost, int _next) { to = _to; cap = _cap; cost = _cost; next = _next; flow = 0; } } edge[M]; int head[N], cntE; int pre[N], dis[N]; bool vis[N]; int src, sink, tot; void dn(int &x, int y) { if(x>y) x=y; } void init() { cntE = 0; memset(head, -1, sizeof head); } void addedge(int u, int v, int cap, int cost) { edge[cntE].init(v, cap, cost, head[u]); head[u] = cntE++; edge[cntE].init(u, 0, -cost, head[v]); head[v] = cntE++; } bool spfa() { queue<int> q; fill(dis, dis+tot, INF); CLR(vis, false, tot); CLR(pre, -1, tot); dis[src] = 0; vis[src] = true; q.push(src); while (q.size()) { int u = q.front(); q.pop(); vis[u] = false; for (int i = head[u]; ~i; i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > edge[i].flow && dis[u]+edge[i].cost < dis[v]) { dis[v] = dis[u]+edge[i].cost; pre[v] = i; if (!vis[v]) { vis[v] = true; q.push(v); } } } } if (pre[sink] == -1) return false; return true; } int MCMF(int &cost) { int flow = 0; cost = 0; while (spfa()) { int f = INF; for (int i = pre[sink]; ~i; i = pre[edge[i^1].to]) { dn(f, edge[i].cap - edge[i].flow); } for (int i = pre[sink]; ~i; i = pre[edge[i^1].to]) { edge[i].flow += f; edge[i^1].flow -= f; cost += edge[i].cost * f; } flow += f; } return flow; }
以上是关于最大流模板的主要内容,如果未能解决你的问题,请参考以下文章