根据最大流最小割原理可知:
在数值上 : 最小割=最大流
这样最小割的数值就可以用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);
}
}
}