全局最小割(模板)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAX_N 500 + 16
#define INF 0x3f3f3f3f
int G[MAX_N][MAX_N];
int v[MAX_N];    // v[i]代表节点i合并到的顶点
int w[MAX_N];    // 定义w(A,x) = ∑w(v[i],x),v[i]∈A
bool visited[MAX_N];    // 用来标记是否该点加入了A集合
int stoer_wagner(int n)
{
    int min_cut = INF;
    for (int i = 0; i < n; ++i){
        v[i] = i;    // 初始还未合并,都代表节点本身
    }
    while (n > 1)
    {
        int pre = 0;    // pre用来表示之前加入A集合的点(在t之前一个加进去的点)
        memset(visited, 0, sizeof(visited));
        memset(w, 0, sizeof(w));
        for (int i = 1; i < n; ++i){
            int k = -1;
            for (int j = 1; j < n; ++j)  // 选取V-A中的w(A,x)最大的点x加入集合
            {
                if (!visited[v[j]])
                {
                    w[v[j]] += G[v[pre]][v[j]];
                    if (k == -1 || w[v[k]] < w[v[j]]){
                        k = j;
                    }
                }
            }
            visited[v[k]] = true;    // 标记该点x已经加入A集合
            if (i == n - 1)    // 若|A|=|V|(所有点都加入了A),结束
            {
                const int s = v[pre], t = v[k];    // 令倒数第二个加入A的点(v[pre])为s,最后一个加入A的点(v[k])为t
                min_cut = min(min_cut, w[t]);    // 则s-t最小割为w(A,t),用其更新min_cut
                for (int j = 0; j < n; ++j)    // Contract(s, t)
                {
                    G[s][v[j]] += G[v[j]][t];
                    G[v[j]][s] += G[v[j]][t];
                }
                v[k] = v[--n];    // 删除最后一个点(即删除t,也即将t合并到s)
            }
// else 继续
            pre = k;
        }
    }
    return min_cut;
}
int main(int argc, char *argv[]){
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF){
        memset(G, 0, sizeof(G));
        while (m--){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            G[u][v] += w;
            G[v][u] += w;
        }
        printf("%d
", stoer_wagner(n));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/13224ACMer/p/4822998.html