1 条题解

  • 0
    @ 2025-8-24 22:12:46

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ix35
    垒球

    搬运于2025-08-24 22:12:46,当前版本为作者最后更新于2020-01-23 00:43:54,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Stoer-Wagner 全局最小割算法

    之前一篇题解没有证明,我来加上一个证明。

    参考文章:全局最小割StoerWagner算法详解 By Oyking

    设原图为 G=(V,E)G=(V,E),最小割为 CEC\in E

    算法基本思想:对于无向图上任意两点 s,ts,t,割去 CC 后,则或者 s,ts,t 处于同一连通块,或者 s,ts,t 处于不同两连通块(显然)。

    1. 对于 s,ts,t 处于同一连通块的情况,根据割的定义,割去 CC 后至少有一个点 jj,与 ss 不在一个连通块内,则 j,tj,t 也不在一个连通块内,那么 jjs,ts,t 都不在一个连通块内,所以凡是 jjs,ts,t 之间的边必须全部割去,如果 (j,s)(j,s) 边被割去,则如果 (j,t)(j,t) 未被割去,(j,s)(j,s) 不割是一种更小的割法(与最小割矛盾),因此如果 (j,s)C(j,s)\in C,则有 (j,t)C(j,t)\in C,所以 s,ts,t 可看作是一个整体,共享所有的边。

    那么,处理完一对 s,ts,t 之间的最小割后,就只有它们处于同一连通块的情况了,也就是做完一对以后就合并一对点,如是进行 n1n-1 次即合并成一个点,算法完成。

    1. 下面主要探讨 s,ts,t 不在一联通块时的答案,即 s,ts,t 之间的最小割,注意 s,ts,t 的选择是任意的。

    构造过程依赖于一个集合 AA,一开始,我们令 A=A=\varnothing,然后我们将所有点(合并了的点算一个)按照某种顺序加入 AA 中。

    加入顺序依赖于权值函数 w(i)w(i),我们令 w(i)w(i) 表示 jAd(j,i)\sum\limits_{j\in A} d(j,i),其中 d(j,i)d(j,i) 表示 j,ij,i 之间的边权(因为求最小割,如果没有边可视为不用割,即 d(j,i)=0d(j,i)=0)。

    算法流程:每次选择 w(i)w(i) 最大的 ii 加入 AA 中,如是进行 V|V'| 次(其中 V|V'| 表示当前图的点数)即可确定所有点加入 AA 的顺序,定义 ord(i)ord(i) 表示第 ii 个加入 AA 的点,令 t=ord(V)t=ord(|V'|),则对于任意一点 sssstt 的最小割即为 w(t)w(t)

    下面来证明一下以上算法的正确性(来自最上面的链接):

    若点 vv 满足:在割去 CC 的图中,存在一个点 uu,在 vv 之前加入 AA,且 uuvv 不在一连通块内,则称 vv 是 Active 的。

    下证对于任意一个 Active 结点 vvCC 中处在 vv 前的部分不小于 w(v)w(v)。如果此结论成立,则因 tt 最后加入 AA,所以 CCtt 前部分就是整个 CC,于是 Cw(t)C\ge w(t),又将 w(t)w(t) 割去后 tt 与其他点都不连通,所以 w(t)w(t) 就是 tt 到之前任意一点的最小割。

    运用数学归纳法,对于第一个 Active 结点 vv,结论成立:因为 vv 前结点都不是 Active 结点,所以都处在一连通块内,所以 vv 与它们都不处在一连通块内,所以想要割去 vv 需要断开它和之前所有点的边,即 w(v)w(v)

    对于 vv 之后的第一个 Active 结点 uu,有 w(u)w(u) 是从 vv 前结点和 vvuu 之间结点与 uu 的边构成的,对于 vv 前面的结点,w(u)w(u) 的这一部分不超过 w(v)w(v)(因为 vv 先加入 AA)。而对于 vvuu 之间结点,与 vv 同样道理地,与 uu 边权相加一定要出现在 CC 中,两者相加,所以完整的 w(u)w(u) 必然大于等于 CCuu 前部分,归纳可得证。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=610,INF=1e9;
    int n,m,x,y,z,s,t,dis[MAXN][MAXN],w[MAXN],dap[MAXN],vis[MAXN],ord[MAXN];
    int proc (int x) {
    	memset(vis,0,sizeof(vis));
    	memset(w,0,sizeof(w));
    	w[0]=-1;
    	for (int i=1;i<=n-x+1;i++) {
    		int mx=0;
    		for (int j=1;j<=n;j++) {
    			if (!dap[j]&&!vis[j]&&w[j]>w[mx]) {mx=j;}
    		}
    		vis[mx]=1,ord[i]=mx;
    		for (int j=1;j<=n;j++) {
    			if (!dap[j]&&!vis[j]) {w[j]+=dis[mx][j];}
    		}
    	}
    	s=ord[n-x],t=ord[n-x+1];
    	return w[t];
    }
    int sw () {
    	int res=INF;
    	for (int i=1;i<n;i++) {
    		res=min(res,proc(i));
    		dap[t]=1;
    		for (int j=1;j<=n;j++) {
    			dis[s][j]+=dis[t][j];
    			dis[j][s]+=dis[j][t];
    		}
    	}
    	return res;
    }
    int main () {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=m;i++) {
    		scanf("%d%d%d",&x,&y,&z);
    		dis[x][y]+=z,dis[y][x]+=z;
    	}
    	printf("%d\n",sw());
    	return 0;
    }
    
    • 1

    信息

    ID
    4638
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者