流網絡定義在有向圖上。無向圖拆成有向圖。然而不拆也能夠。ios
最小割是一個邊集\((S,T)\),將點分紅 \(S,T=V-S\) 兩個集合c++
最小割的容量\(c(S,T) = \sum_{u \in S} \sum_{v \in T} c(u,v)\)網絡
因此刪去割集中全部邊後,從s到t不連通。最大流後割集上的邊(從s到t方向)滿流。spa
(從t到s不必定。)code
最大流後的殘量網絡中,滿流的邊不必定是割邊,割邊必定滿流ci
最小割的容量是割邊的容量和,等於最大流的流量string
最小割惟一意味着點集惟一it
當存在強連通份量(可能只是一個點) \(u\),知足在殘量網絡上沒有s到u和u到t的路徑,那麼u能夠分配到\(S\)或\(T\)中,最小割不惟一。io
因此就是從s開始bfs,再從t倒着bfs(看反向邊流量)模板
一個典型的栗子:
1 2 1
2 3 1
2 3 1
3 4 1
判斷某條邊是否能夠在割集中,是否一定在割集中
求出scc後再斷定
能夠發現,求scc後,scc之間連的單向邊是由於有一個方向滿流(有向圖的話,默認反向弧滿流)
jcvb:
在殘餘網絡上跑tarjan求出全部SCC,記id[u]爲點u所在SCC的編號。顯然有id[s]!=id[t](不然s到t有通路,能繼續增廣)。
- 對於任意一條滿流邊(u,v),(u,v)可以出如今某個最小割集中,當且僅當id[u]!=id[v];
- 對於任意一條滿流邊(u,v),(u,v)一定出如今最小割集中,當且僅當id[u] == id[s]且id[v] == id[t]。
證實:
①
<==將每一個SCC縮成一個點,獲得的新圖就只含有滿流邊了。那麼新圖的任一s-t割都對應原圖的某個最小割,從中任取一個把id[u]和id[v]割開的割便可證實。
②
<==:假設將(u,v)的邊權增大,那麼殘餘網絡中會出現s->u->v->t的通路,從而能繼續增廣,因而最大流流量(也就是最小割容量)會增大。這即說明(u,v)是最小割集中必須出現的邊。
反向弧容量爲c,無需加兩次
也能夠加兩次QwQ
//zoj2587 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 1005, M = 20005, inf = 1e9; int n, m, s, t; struct edge {int v, ne, c, f;} e[M]; int cnt = 1, h[N]; inline void ins(int u, int v, int c) { e[++cnt] = (edge) {v, h[u], c, 0}; h[u] = cnt; e[++cnt] = (edge) {u, h[v], c, 0}; h[v] = cnt; } int cur[N], vis[N], d[N], head, tail, q[N]; bool bfs() { memset(vis, 0, sizeof(vis)); head = tail = 1; q[tail++] = s; d[s] = 0; vis[s] = 1; while(head != tail) { int u = q[head++]; for(int i=h[u]; i; i=e[i].ne) { int v = e[i].v; if(!vis[v] && e[i].c > e[i].f) { vis[v] = 1; d[v] = d[u] + 1; q[tail++] = v; if(v == t) return true; } } } return false; } int dfs(int u, int a) { //printf("dfs %d %d\n", u, a); if(u==t || a==0) return a; int flow = 0, f; for(int &i=cur[u]; i; i=e[i].ne) { int v = e[i].v; if(d[v] == d[u]+1 && (f = dfs(v, min(a, e[i].c-e[i].f))) > 0) { flow += f; e[i].f += f; e[i^1].f -= f; a -= f; if(a == 0) break; } } if(a) d[u] = -1; return flow; } int dinic() { int flow = 0; while(bfs()) { for(int i=1; i<=n; i++) cur[i] = h[i]; flow += dfs(s, inf); } return flow; } int bfs2(int s) { int ans = 1; memset(vis, 0, sizeof(vis)); head = tail = 1; q[tail++] = s; vis[s] = 1; while(head != tail) { int u = q[head++]; for(int i=h[u]; i; i=e[i].ne) { int v = e[i].v; if(vis[v] || e[i].c==e[i].f) continue; vis[v] = 1; ans++; q[tail++] = v; } } return ans; } int bfs3(int s) { int ans = 1; memset(vis, 0, sizeof(vis)); head = tail = 1; q[tail++] = s; vis[s] = 1; while(head != tail) { int u = q[head++]; for(int i=h[u]; i; i=e[i].ne) { int v = e[i].v; if(vis[v] || e[i^1].c==e[i^1].f) continue; vis[v] = 1; ans++; q[tail++] = v; } } return ans; } int main() { freopen("in", "r", stdin); ios::sync_with_stdio(false); cin.tie(); cout.tie(); while(true) { cin >> n >> m >> s >> t; if(n == 0) break; cnt = 1; memset(h, 0, sizeof(h)); for(int i=1; i<=m; i++) { int u, v, c; cin >> u >> v >> c; ins(u, v, c); } dinic(); int cnt1 = bfs2(s), cnt2 = bfs3(t); if(cnt1 + cnt2 < n) cout << "AMBIGUOUS" << endl; else cout << "UNIQUE" << endl; } }
//[AHOI2009]最小割 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int N = 4005, M = 6e4+5, inf = 1e9; int n, m, s, t; struct edge {int u, v, ne, c, f;} e[M<<1]; int cnt=1, h[N]; inline void ins(int u, int v, int c) { e[++cnt] = (edge) {u, v, h[u], c, 0}; h[u] = cnt; e[++cnt] = (edge) {v, u, h[v], 0, 0}; h[v] = cnt; } int cur[N], vis[N], d[N], head, tail, q[N]; bool bfs() { memset(vis, 0, sizeof(vis)); head = tail = 1; q[tail++] = s; d[s] = 0; vis[s] = 1; while(head != tail) { int u = q[head++]; for(int i=h[u]; i; i=e[i].ne) { int v = e[i].v; if(!vis[v] && e[i].c > e[i].f) { vis[v] = 1; d[v] = d[u]+1; q[tail++] = v; if(v == t) return true; } } } return false; } int dfs(int u, int a) { if(u==t || a==0) return a; int flow = 0, f; for(int &i=cur[u]; i; i=e[i].ne) { int v = e[i].v; if(d[v] == d[u]+1 && (f = dfs(v, min(a, e[i].c-e[i].f))) > 0) { flow += f; e[i].f += f; e[i^1].f -= f; a -= f; if(a == 0) break; } } if(a) d[u] = -1; return flow; } int dinic() { int flow = 0; while(bfs()) { for(int i=1; i<=n; i++) cur[i] = h[i]; flow += dfs(s, inf); } return flow; } int dfn[N], low[N], dfc, scc, belong[N], st[N], top; void dfs(int u) { dfn[u] = low[u] = ++dfc; st[++top] = u; for(int i=h[u]; i; i=e[i].ne) if(e[i].c > e[i].f) { int v = e[i].v; if(!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(!belong[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { scc++; while(true) { int x = st[top--]; belong[x] = scc; if(x == u) break; } } } int main() { freopen("in", "r", stdin); ios::sync_with_stdio(false); cin.tie(); cout.tie(); cin >> n >> m >> s >> t; for(int i=1; i<=m; i++) { int u, v, c; cin >> u >> v >> c; ins(u, v, c); } dinic(); for(int i=1; i<=n; i++) if(!dfn[i]) dfs(i); //for(int i=1; i<=n; i++) printf("dfn %d %d %d\n", i, dfn[i], belong[i]); int a = belong[s], b = belong[t]; for(int i=1; i<=m; i++) { int u = e[i<<1].u, v = e[i<<1].v; if(e[i<<1].c == e[i<<1].f && belong[u] != belong[v]) cout << 1 << ' '; else cout << 0 << ' '; if(e[i<<1].c == e[i<<1].f && belong[u] == a && belong[v] == b) cout << 1 << '\n'; else cout << 0 << '\n'; } }