流网络定义在有向图上。无向图拆成有向图。然而不拆也能够。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'; } }