zoukankan      html  css  js  c++  java
  • [学习笔记]全局最小割StoerWagner算法

    概念

    无向图的割:删除割集中的边可以使无向图不联通。
    \(ST\)割:使得\(S\)\(T\)不联通的割称做\(ST\)割。
    \(ST\)最小割:\(ST\)割中边权和最小的方案。
    全局最小割:边权和最小的割。
    诱导割:一个割在子图中所存在的部分,称做诱导割,其类似于诱导子图概念。

    算法流程:

    伪代码
    def MinimumCutPhase(G, w, a):
        A ← {a}
        while A ≠ V:
            把与A联系最紧密(most tightly)的顶点加入A中
        cut-of-the-phase ← w(A \ t, t)
        合并最后两个加入到A的顶点s、t
        return cut-of-the-phase
    
    def StoerWagner(G, w, a):
        while |V| > 1
            MinimumCutPhase(G, w, a)
            根据返回值更新最小割
    
    

    其中\(w(A,v)\)\(v\)到集合\(A\)中的点的所有边权之和

    最紧密的指:\(\max(w(A,x))\)\(x\)

    证明:

    最小割,要么是\(s-t\)割,要么是非\(s-t\)割,后者将两点合并不影响。

    考虑证明我们\(MinimumCutPhase\)找出来的\(s−t\)\(cut-of-the-phase\)为什么是最小的。

    \(A_u\)为加入\(u\)前的\(A\)集合。

    \(C\)为任意\(s-t\)割,\(C_u\)\(A_u + {u}\)部分的诱导割。

    \(u\)为活跃的当\(A_u\)的最后一个点与\(u\)\(C\)中分属两边。

    考虑归纳证明。

    第一个活跃节点显然满足条件。

    \(v\)满足条件,\(u\)为下一个活跃节点。

    \(w(A_u,u) = w(A_v,u) + w(A_u - A_v,u) = \alpha\)

    \(w(A_v,u) \leq w(A_v,v) \leq w(C_v)\)
    \(w(C_v) + w(A_u - A_v,u) \leq w(C_u)\)

    两式联立可得原式。

    全局最小割StoerWagner算法
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long LL;
    
    const int MAXN = 3100;
    
    LL mat[MAXN][MAXN];
    LL weight[MAXN];
    bool del[MAXN], vis[MAXN];;
    int n, m, st;
    
    void init() {
        memset(mat, 0, sizeof(mat));
        memset(del, 0, sizeof(del));
    }
    
    LL StoerWagner(int &s, int &t, int cnt) {
        memset(weight, 0, sizeof(weight));
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= n; ++i)
            if(!del[i]) {t = i; break; }
        while(--cnt) {
            vis[s = t] = true;
            for(int i = 1; i <= n; ++i) if(!del[i] && !vis[i]) {
                weight[i] += mat[s][i];
            }
            t = 0;
            for(int i = 1; i <= n; ++i) if(!del[i] && !vis[i]) {
                if(weight[i] >= weight[t]) t = i;
            }
        }
        return weight[t];
    }
    
    void merge(int s, int t) {
        for(int i = 1; i <= n; ++i) {
            mat[s][i] += mat[t][i];
            mat[i][s] += mat[i][t];
        }
        del[t] = true;
    }
    
    LL solve() {
        LL ret = -1;
        int s, t;
        for(int i = n; i > 1; --i) {
            if(ret == -1) ret = StoerWagner(s, t, i);
            else ret = min(ret, StoerWagner(s, t, i));
            merge(s, t);
        }
        return ret;
    }
    
    int main() {
        while(scanf("%d%d", &n, &m) != EOF) {
            if(n == 0 && m == 0) break;
            init();
            while(m--) {
                int x, y, z;
                scanf("%d%d%d", &x, &y, &z);
                mat[x][y] += z;
                mat[y][x] += z;
            }
            cout<<solve()<<endl;
        }
    }
    
  • 相关阅读:
    物联网普而不及 仍缺杀手级应用
    05-if和switch的简单比较
    05-if使用注意
    04-关系运算符使用注意
    03-sizeof的用法
    01-scanf函数的注意点
    01-变量的内存分析
    06-自定义构造方法
    06-构造方法
    05-id的使用
  • 原文地址:https://www.cnblogs.com/dixiao/p/15775362.html
Copyright © 2011-2022 走看看