利用Stoer-Wagner算法求无向图最小割

直接给出算法描述和过程实现:

算法步骤:
1. 设最小割cut=INF, 任选一个点s到集合A中, 定义W(A, p)为A中的所有点到A外一点p的权总和.
2. 对刚才选定的s, 更新W(A,p)(该值递增).
3. 选出A外一点p, 且W(A,p)最大的作为新的s, 若A!=G(V), 则继续2.
4. 把最后进入A的两点记为s和t, 用W(A,t)更新cut.
5. 新建顶点u, 边权w(u, v)=w(s, v)+w(t, v), 删除顶点s和t, 以及与它们相连的边.
6. 若|V|!=1则继续1.

然后题目POJ2914的意思是去掉一些边使原图变成两个连通分量并且去掉边的权值之和最小,如果要是去掉的边最少的话让所有边权值为1就好了

int n,m;
int v[maxn],d[maxn],vis[maxn];
int G[maxn][maxn];

v表示经过合并之后的节点,d表示w(A,v[i])

然后直接给出实现:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=505;
 6 const int INF=0x7f7f7f7f;
 7 int n,m;
 8 int v[maxn],d[maxn],vis[maxn];
 9 int G[maxn][maxn];
10 int Stoer_Wagner(int n)
11 {
12     int res=INF;
13     for(int i=0;i<n;i++) v[i]=i;//初始化第i个结点就是i
14     while(n>1)
15     {
16         int maxp=1,prev=0;
17         for(int i=1;i<n;i++)
18         {
19             //初始化到已圈集合的割大小,并找出最大距离的顶点
20             d[v[i]]=G[v[0]][v[i]];
21             if(d[v[i]]>d[v[maxp]]) maxp=i;
22         }
23         memset(vis,0,sizeof(vis));
24         vis[v[0]]=1;
25         for(int i=1;i<n;i++)
26         {
27             if(i==n-1)
28             {
29                 //只剩最后一个没加入集合的点,更新最小割
30                 res=min(res,d[v[maxp]]);
31                 for(int j=0;j<n;j++)
32                 {
33                     //合并最后一个点以及推出它的集合中的点
34                     G[v[prev]][v[j]]+=G[v[j]][v[maxp]];
35                     G[v[j]][v[prev]]=G[v[prev]][v[j]];
36                 }
37                 //第maxp个节点去掉,第n个节点变成第maxp个
38                 v[maxp]=v[--n];
39             }
40             vis[v[maxp]]=1;
41             prev=maxp;
42             maxp=-1;
43             for(int j=1;j<n;j++)
44             //将上次求的maxp加入集合,合并与它相邻的边到割集
45                 if(!vis[v[j]])
46                 {
47                     d[v[j]]+=G[v[prev]][v[j]];
48                     if(maxp==-1||d[v[maxp]]<d[v[j]]) maxp=j;
49                 }
50         }
51     }
52     return res;
53 }
54 int main()
55 {
56     while(scanf("%d%d",&n,&m)!=EOF)
57     {
58         memset(G,0,sizeof(G));
59         int x,y,z;
60         while(m--)
61         {
62             scanf("%d%d%d",&x,&y,&z);
63             G[x][y]+=z;
64             G[y][x]+=z;
65         }
66         printf("%d\n",Stoer_Wagner(n));
67     }
68     return 0;
69 }

像这种完全成熟的算法,会用即可,不用再这个的基础上做任何改动

原文地址:https://www.cnblogs.com/aininot260/p/9448666.html

时间: 2024-09-30 07:43:17

利用Stoer-Wagner算法求无向图最小割的相关文章

求无向图最小割

先解释下名词的意思. 无向图的割:就是去掉一些边,使得原图不连通,最小割就是要去掉边的数量最小. 解决这个问题的常用办法就是Stoer-Wagner 算法: 先说下这个算法的步骤后面给出证明: 1.min=MAXINT,固定一个顶点P 2.从点P用类似prim的s算法扩展出"最大生成树",记录最后扩展的顶点和最后扩展的边 3.计算最后扩展到的顶点的切割值(即与此顶点相连的所有边权和),若比min小更新min 4.合并最后扩展的那条边的两个端点为一个顶点 5.转到2,合并N-1次后结束

Tarjan 算法求无向图的割顶和桥

#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N = 250; int head[N], low[N], dfn[N], fa[N]; int n, m, now = 1, Tarjan_clock; bool is_cut[N]; struct Node{ int u, v, nxt; }E[N]; inline int read()

BZOJ1001[BeiJing2006]狼抓兔子(无向图最小割)

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 这题的题意其实就是求一个最小割,但是由于是无向图,所以加边的时候,两边的流量都要是输入的权值,然后就是一个dinic求一下最小割. 但是这题貌似有很高超的技巧来搞,可以把平面图上的最小割转成对偶图上的最短路来做,这样可以起到很明显的优化效果.现在还不是很明白,如果以后明白了,会再来更新. dinic: #include <cstdio> #include <cstring&g

Hdu 3691 Nubulsa Expo(无向图最小割)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3691 思路:无向图最小割模板题. 流量最小且汇点自定,则可在最小割T集中任选一点当做汇点. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define debu using namespace std; const int maxn=350; const in

POJ2914 (未解决)无向图最小割|Stoer-Wagner算法|模板

还不是很懂,贴两篇学习的博客: http://www.hankcs.com/program/algorithm/poj-2914-minimum-cut.html http://blog.sina.com.cn/s/blog_700906660100v7vb.html 算法步骤: 1. 设最小割cut=INF, 任选一个点s到集合A中, 定义W(A, p)为A中的所有点到A外一点p的权总和. 2. 对刚才选定的s, 更新W(A,p)(该值递增). 3. 选出A外一点p, 且W(A,p)最大的作为

无向图最小割 stoer_wagner算法

1 const int MAX_N = 1; 2 int G[MAX_N][MAX_N]; 3 int v[MAX_N]; // v[i]代表节点i合并到的顶点 4 int w[MAX_N]; // 定义w(A,x) = ∑w(v[i],x),v[i]∈A 5 bool visited[MAX_N]; // 用来标记是否该点加入了A集合 6 7 int stoer_wagner(int n) 8 { 9 int min_cut = inf; 10 for (int i = 0; i < n; +

hdoj 2435 There is a war 【求原图最小割已经分成的两个点集 + 枚举两点集里面的点建新边 求残量网络的最大最小割】

There is a war Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 993    Accepted Submission(s): 283 Problem Description There is a sea. There are N islands in the sea. There are some directional

hdoj 3987 Harry Potter and the Forbidden Forest 【求所有最小割里面 最少的边数】

Harry Potter and the Forbidden Forest Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1802    Accepted Submission(s): 602 Problem Description Harry Potter notices some Death Eaters try to slip

poj1966Cable TV Network——无向图最小割(最大流)

题目:http://poj.org/problem?id=1966 把一个点拆成入点和出点,之间连一条边权为1的边,跑最大流即最小割: 原始的边权赋成inf防割: 枚举源点和汇点,直接相邻的两个点不必枚举: 注意:1.源点为枚举点i的出点,汇点为枚举点j的入点: 2.读入方式,免空格: 3.在dinic跑最大流的过程中,会改变边权,因此每次枚举都要复制一组边跑最大流,以免影响后面: 另:数据中的点从0开始,所以读入的时候++来使用. 代码如下: #include<iostream> #incl