Stoer Wagner 算法主要是解决无向图最小割的问题。
给定一张无向图,每一条边都有其花费,求最少能使这张图不连通应割掉的边数。
原作者论文,侵删
<h1>解题思路</h1>
首先我们可以使用网络流暴力跑,也就是随机一个源点然后枚举汇点跑最大流那种,但是时间复杂度有点高,上界是 $O(n^3m)$。
于是 就有了 Stoer Wagner 算法来解决这个问题。
我们先描述一下这个算法的一般流程:
- $min = INF$,固定一个顶点 $P$
- 从点 $P$ 用 “类似” prim 的算法扩展出 “最大生成树” ,记录最后扩展的顶点和最后扩展的边
- 计算最后扩展到的顶点的切割值(即与此顶点相连的所有边权和),若比 min 小更新 min
- 合并最后扩展的那条边的两个端点为一个顶点(当然他们的边也要合并,这个好理解吧?)
- 转到 $2$,合并 N-1 次后结束
- min 即为所求,输出 min
相信大家看到这里一定是懵逼的...那么建议大家先阅读代码,然后结合论文食用。
<h1>代码</h1>
#include <algorithm> #include <iostream> #include <cstring> #include <climits> #include <cstdio> #include <vector> #include <cstdlib> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define Re register #define LL long long #define U unsigned #define FOR(i,a,b) for(Re int i = a;i <= b;++i) #define ROF(i,a,b) for(Re int i = a;i >= b;--i) #define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c) #define SROF(i,a,b,c) for(Re int i = a;i >= b;i-=c) #define CLR(i,a) memset(i,a,sizeof(i)) #define BR printf("--------------------n") #define DEBUG(x) std::cerr << #x << '=' << x << std::endl const int MAXN = 1000+5; int fMAXN,dist[MAXN]; bool vis[MAXN],del[MAXN]; int N,M; inline void init(){ CLR(f,0);CLR(del,false); } int contract(int &s,int &t){ int min=0; CLR(dist,0);CLR(vis,0); FOR(i,1,N){ int k = -1,max = -1; FOR(j,1,N){ if(!del[j] && !vis[j] && dist[j] > max){ k = j;max = dist[j]; } } if(k == -1) return min; s = t,t = k; min = max; vis[k] = true; FOR(j,1,N){ if(!del[j] && !vis[j]) dist[j] += fk; } } return min; } int SW(){ int min = INT_MAX; FOR(i,1,N-1){ int s,t; min = std::min(min,contract(s,t)); del[t] = true; if(min == 0) return 0; FOR(j,1,N) if(!del[j]) fs = (fj += fj); } return min; } inline void Solve(){ init(); FOR(i,1,M){ int u,v,w;scanf("%d%d%d",&u,&v,&w); u++;v++; fu = (fv += w); } printf("%dn",SW()); } int main(){ while(~scanf("%d%d",&N,&M)) Solve(); return 0; }