1. 程式人生 > >dinic求最小割邊集 UVA 10480

dinic求最小割邊集 UVA 10480

根據最大流最小割原理可知:
在數值上 : 最小割=最大流
這樣最小割的數值就可以用dinic跑出來,然後如果要是求最小割邊集的話,這樣的方法就需要稍加改進。
那麼我們需要在最大流之後把殘餘網路中的點重新分為兩類,一類為源點組,一類為匯點組,通過從s開始的dfs找到能夠到達的點與源點一組,否則與匯點一組,這樣在掃一遍所有的邊,判斷邊的兩個點是否分別在這兩組,如果是的話,那麼這條邊就是最小割邊集中的一條。
下面以 UVA 10480 為例

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10
; #define met(a, b) memset(a, b, sizeof(a)) struct EDGE { int to, next, vol, tot; } edges[maxn]; const int inf = 0x3f3f3f3f; int n, m, cur[maxn], a[maxn], ccnt = 0; int Head[maxn], edgesNum = 0, S = 1, T = 2, u[maxn], v[maxn], dep[maxn]; void addEdge(int u, int v, int vol); bool bfs(int s, int t);//分層
int dfs(int u, int flow); int solve(int s, int t);//dinic演算法 void dfs1(int u);//掃一遍殘餘網路 int main() { while(~scanf("%d%d", &n, &m) && n + m) { int x, y, w; met(a, 0); met(Head, -1); for(int i = 0; i < m; i++) { scanf("%d%d%d", &x, &y, &w); addEdge(x, y, w); u[i] = x; v[i] = y; } solve(S, T); } return
0; } void addEdge(int u, int v, int vol) { edges[edgesNum].to = v; edges[edgesNum].vol = vol; edges[edgesNum].tot = vol; edges[edgesNum].next = Head[u]; Head[u] = edgesNum++; edges[edgesNum].to = u; edges[edgesNum].vol = vol; edges[edgesNum].tot = vol; edges[edgesNum].next = Head[v]; Head[v] = edgesNum++; } bool bfs(int s, int t) { met(dep, -1); dep[s] = 1; queue<int> q; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for(int e = Head[u]; e != -1; e = edges[e].next) { int v = edges[e].to; if(dep[v] == -1 && v != s && edges[e].vol > 0) { dep[v] = dep[u] + 1; q.push(v); } } } if(dep[t] == -1) return 0; else return 1; } int dfs(int u, int flow) { if(u == T) return flow; for(int &e = cur[u]; ~e; e = edges[e].next) { int v = edges[e].to; if(dep[v] == dep[u] + 1 && edges[e].vol > 0) { int di = dfs(v, min(flow, edges[e].vol)); if(di > 0) { edges[e].vol -= di; edges[e ^ 1].vol += di; return di; } } } return 0; } int solve(int s, int t) { int max_flow = 0; while(bfs(s, t)) { for(int i = 1; i <= n; i++) cur[i] = Head[i]; while(int di = dfs(s, inf)) { max_flow += di; } } //一定要在最大流跑完之後才能執行dfs1(int u)這個函式 dfs1(s); //掃一遍所有的邊集 for(int i = 0; i < m; i++) { //判斷起點與終點是否在同一組 if((!a[u[i]] && a[v[i]]) || (!a[v[i]] && a[u[i]])) { printf("%d %d\n", u[i], v[i]); } } puts(""); return max_flow; } void dfs1(int u) { a[u] = 1; for(int e = Head[u]; e != -1; e = edges[e].next) { int v = edges[e].to; //只有在殘餘網路流>0的情況下才能繼續dfs if(!a[v] && edges[e].vol > 0) { dfs1(v); } } }