寻找全局最小割(Stoer-Wagner 算法)

给定无向图,求全局最小割,Stoer-Wagner 算法过程如下:

方便起见,使用邻接矩阵存图,重边累加边权,记为 \(adj\).

维护活跃集合 \(act\),重复下面操作 \(n-1\) 轮:

维护一个集合 \(A\),定义

\[W_u = \sum_{v\in A}{adj_{u,v}} \]

\(u\) 与集合 \(A\) 中所有点的边权累加和.

重复 \(|act|\) 轮,每轮寻找 \(W_u\) 最大值加入集合 \(A\),最终所有点均加入集合 \(A\).

记最后加入集合 \(A\) 的点为 \(t\),倒数第二加入集合 \(A\) 的点为 \(s\),不难发现,\(W_t\) 是割 \(\{t\} \mid V\setminus \{t\}\).

Stoer-Wagner 定理指出:此时 \(W_t\)\(s,t\) 的最小割,因此可以做如下操作:取 \(W_t\) 作为全局最小割候选,合并 \(s,t\).

\(W_t\) 不是全局最小割,合并 \(s,t\) 不影响其他割,从而保证了正确性.

时间复杂度 \(\mathcal{O}(n^3)\).

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const ll INF = 9e18;

void solve(){
    int n,m;
    cin >> n >> m;

    vector<vector<ll>> adj(n+1,vector<ll>(n+1));
    for (int i=0;i<m;i++){
        int u,v,w;
        cin >> u >> v >> w;
        adj[u][v] += w;
        adj[v][u] += w;
    }

    vector<int> act(n);
    iota(act.begin(),act.end(),1);
    vector<ll> W(n+1);
    vector<bool> vis(n+1);

    ll minn = INF;

    while (act.size()>1){
        fill(W.begin(),W.end(),0);
        fill(vis.begin(),vis.end(),false);
        int len = act.size();
        int pre = -1;

        for (int t=1;t<=len;t++){
            int cur = -1;
            ll mx = -INF;
            for (auto& v:act){
                if (!vis[v] && W[v]>mx){
                    mx = W[v];
                    cur = v;
                }
            }

            if (t==len){
                minn = min(minn,W[cur]);
                for (auto& v:act){
                    if (v==pre || v==cur) continue;
                    adj[pre][v] += adj[cur][v];
                    adj[v][pre] += adj[v][cur]; 
                }

                auto it = find(act.begin(),act.end(),cur);
                act.erase(it);
            }
            else{
                pre = cur;
                vis[cur] = true;
                for (auto& v:act){
                    if (!vis[v]){
                        W[v] += adj[cur][v];
                    }
                }              
            }
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-08-28 10:46  kzssCCC  阅读(3)  评论(0)    收藏  举报