dinic求最小割邊集 UVA 10480
阿新 • • 發佈:2019-01-09
根據最大流最小割原理可知:
在數值上 : 最小割=最大流
這樣最小割的數值就可以用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);
}
}
}