首先是当年stoer和wagner两位大佬发表的关于这个算法的论文:A Simple Min-Cut Algorithm

直接上算法部分:

                          分割线                          begin

在这整篇论文中,我们假设一个普通无向图G=(V,E),其中每条边e都有一个正实数权值w(e)。

  如果我们知道:怎样找到两个节点s,t,以及怎样得到对于s-t的最小割,我们就几乎解决了整个问题:

  定理2.1:

    设s和t是图G中的两个节点,设G/{s,t}是合并s和t后得到的图,

    则图G的全局最小割可以通过“图G对于s-t的最小割”和“图G/{s,t}的全局最小割”得到。

定理说明:

  若图G存在一个全局最小割,使得s和t被分割,那么,图G的s-t最小割就等于图G的全局最小割。

  否则(即全局最小割没有分割s和t),图G的全局最小割就等于图G/{s,t}的全局最小割。

因此,我们可以使用一个寻找任意s-t最小割的程序来构建一个递归算法,从而寻找一个图的全局最小割。

下面的算法(使用一些骚操作搜索方法),可以产生我们想得到的s-t最小割。

MinimumCutPhase(G,w,a)  //分阶段(phase),每个阶段都产生相应的当前阶段最小割

{

  A←{a}

  while( A ≠ V )

  {

    选取“最紧密相连的点”加入A

  }

  记录当前阶段的割,并且合并最后加入的两个点

}

呵,听起来就很玄乎,什么玩意儿呢,下面有解释。

A是作为V的一个子集,开始时是空集,我们任取一个点,加入到A中,然后通过某个规则不断地往A中加入点,直到A == V为止,那是什么规则呢?

  在每一步的加点操作中,我们选择集合(V - A)中和A“最紧密相连的点”加入A,那什么是“最紧密相连的点”呢?

    设:点y∈ V - A ,且点y为与集合A直接相连的点,所有点y的集合为Y;

      所有与集合A直接相连的边的权重总和为w(A,y);

    则:“最紧密相连的点” z 满足: z ∈ Y,并且w(A,z)为所有w(A,y)中最大的。

    通俗的说,就是V - A集合里,找一个直接与A相连的点,这个点是 Σ(该点所有与A直接相连的边的权值) 最大的那个。

(不难看出,这是一种类似于prim算法生成类似最大生成树的算法)

在我们不断往A加点的过程中,记录下最后加入A的两个点,记为s和t,对这两个点进行合并操作(merge):

  删除点s和点t,加入新的点u作为代替,所有原本从s或t点出发的边(edge< s , t >除外,这条边删除;并且设这些边到达的点为x),都用一条新的edge< u , x >代替;

  并且 edge< u , x >.weight = edge< s , x >.weight + edge< t , x >.weight ;  (若某条边不存在,则定义其weight=0)

  (当然需要注意的是,所有讨论都是建立在无向图上,故这里的出发、到达不代表这条边的方向,只是单纯描述该边的两个端点)

然后,我们把当前分割s和t的割(cut),叫做阶段割the-cut-of-phase),不难得到,阶段割等于w(A,t) (注意,此处的集合A表示加入点t前的集合A);

then,所有阶段割中最小的,即本算法的结果,即我们想求的全局最小割。

MinimumCut(G,w,a)

{

  while(|V| > 1)

  {

    MinimumCutPhase(G,w,a)

    if(阶段割 < 当前全局最小割) 当前全局最小割 = 阶段割

  }

}

最后,注意到节点a在本算法整个过程中是一直不变的,实际上它也可以在每个阶段(phase)进行任意选择。

                           分割线                          end

然后是论文中的example部分:

                           分割线                          begin

这是第一次MinimumCutPhase(G,w,a)操作前和操作后的样子,

在此次MinimumCutPhase(G,w,a)操作中,进入集合A的点的顺序为: 2 → 3 → 4 → 7 → 8 → 6 → 5(s) → 1(t) ;

显然,此次的阶段割cut-of-the-phase.weight = w(A,t) = edge<1,2>.w + edge<1,5>.w = 5 ;

之后的操作与此类似,不再赘述,可以自行对照论文中的FIG。

                           分割线                          end

当然,上stoer和wagner两位巨老当初的论文,装逼成分多余实际效用= =,感觉自己翻译也翻译的像一坨shit一样;

更多细节更深理解还请看中文:http://files.cnblogs.com/files/dilthey/stoer-wagner%E7%AE%97%E6%B3%95.pdf

先上算法模板以及解释:

 #include<cstring>
#define MAXN 505
#define INF 0x3f3f3f3f
int n,m;//n个点,m条边
int edge[MAXN][MAXN],dist[MAXN];
bool vis[MAXN],bin[MAXN];
void init()
{
memset(edge,,sizeof(edge));
memset(bin,,sizeof(bin));
}
int merge(int &s,int &t)//对应论文中的MinimumCutPhase()
{
memset(dist,,sizeof(dist));
memset(vis,,sizeof(vis));
int k,mincut,maxc;
for(int i=;i<=n;i++)
{
k=-, maxc=-;
for(int j=;j<=n;j++) if(!bin[j] && !vis[j] && dist[j] > maxc) {k=j;maxc=dist[j];}
//寻找"the most tightly connected vertex"
if(k == -) return mincut;
vis[k]=true;//点k加入集合A
s=t; t=k;//不断移动s和t,保证他们是最后进入集合A的两个点
mincut=maxc;//不断更新mincut为w(A,t)
for(int j=;j<=n;j++) if(!bin[j] && !vis[j]) dist[j]+=edge[k][j];//计算所有的w(A,y)
}
return mincut;
}
int stoer_wagner()
{
int mincut=INF,s,t,ans;
for(int i=;i<=n-;i++)//merge(s,t)一次减少一个点,|V|要从n减少到1,故要进行n-1次
{
ans=merge(s,t);
bin[t]=;//把t合并到s中
if(ans<mincut) mincut=ans;
if(mincut==) return ;
for(int j=;j<=n;j++) if(!bin[j]) edge[s][j]=(edge[j][s]+=edge[j][t]);//更新所有从s出发的边
}
return mincut;
}

时间复杂度O(n³);

再说POJ2914,

题目链接:http://poj.org/problem?id=2914

有了模板之后,就是模板题;

当然,需要注意的是,这道题目里,n个点标号是0~n-1,用这个模板的话需要在输入的时候自己+1;

另外,这道题目的输入有重边,所以存边的时候,使用“+=”,而不是“=”;

 #include<cstdio>
#include<cstring>
#define MAXN 505
#define MAXM MAXN*MAXN/2
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int edge[MAXN][MAXN],dist[MAXN];
bool vis[MAXN],bin[MAXN];
void init()
{
memset(edge,,sizeof(edge));
memset(bin,,sizeof(bin));
}
int merge(int &s,int &t)
{
memset(dist,,sizeof(dist));
memset(vis,,sizeof(vis));
int k,mincut,maxc;
for(int i=;i<=n;i++)
{
k=-, maxc=-;
for(int j=;j<=n;j++) if(!bin[j] && !vis[j] && dist[j] > maxc) {k=j;maxc=dist[j];}
if(k == -) return mincut;
vis[k]=true;
s=t; t=k;
mincut=maxc;
for(int j=;j<=n;j++) if(!bin[j] && !vis[j]) dist[j]+=edge[k][j];
}
return mincut;
}
int stoer_wagner()
{
int mincut=INF,s,t,ans;
for(int i=;i<=n-;i++)
{
ans=merge(s,t);
bin[t]=;
if(ans<mincut) mincut=ans;
if(mincut==) return ;
for(int j=;j<=n;j++) if(!bin[j]) edge[s][j]=(edge[j][s]+=edge[j][t]);
}
return mincut;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
edge[a+][b+]+=c;
edge[b+][a+]+=c;
}
printf("%d\n",stoer_wagner());
}
}

POJ 2914 - Minimum Cut - [stoer-wagner算法讲解/模板]的更多相关文章

  1. POJ 2914 Minimum Cut Stoer Wagner 算法 无向图最小割

    POJ 2914 题意:给定一个无向图 小于500节点,和边的权值,求最小的代价将图拆为两个联通分量. Stoer Wagner算法: (1)用类似prim算法的方法求"最大生成树" ...

  2. POJ 2914 Minimum Cut 最小割算法题解

    最标准的最小割算法应用题目. 核心思想就是缩边:先缩小最大的边.然后缩小次大的边.依此缩小 基础算法:Prime最小生成树算法 只是本题測试的数据好像怪怪的,相同的算法时间执行会区别非常大,并且一样的 ...

  3. POJ 2914 Minimum Cut 最小割图论

    Description Given an undirected graph, in which two vertices can be connected by multiple edges, wha ...

  4. POJ 2914 Minimum Cut【最小割 Stoer-Wangner】

    题意:求全局最小割 不能用网络流求最小割,枚举举汇点要O(n),最短增广路最大流算法求最大流是O(n2m)复杂度,在复杂网络中O(m)=O(n2),算法总复杂度就是O(n5):就算你用其他求最大流的算 ...

  5. POJ 2914 Minimum Cut

    Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 9319   Accepted: 3910 Case ...

  6. POJ 2914 Minimum Cut (全局最小割)

    [题目链接] http://poj.org/problem?id=2914 [题目大意] 求出一个最小边割集,使得图不连通 [题解] 利用stoerwagner算法直接求出全局最小割,即答案. [代码 ...

  7. POJ 2914 Minimum Cut 全局最小割

    裸的全局最小割了吧 有重边,用邻接矩阵的时候要小心 #include<iostream> #include<cstdio> #include<bitset> #in ...

  8. poj Minimum( CutStoer Wagner算法)

    Minimum Cut 题目: 给出一张图.要求你删除最小割权和图. 算法分析: ////////////////////     转载 --- ylfdrib   ///////////////// ...

  9. POJ2914 Minimum Cut —— 最小割

    题目链接:http://poj.org/problem?id=2914 Minimum Cut Time Limit: 10000MS   Memory Limit: 65536K Total Sub ...

随机推荐

  1. Java实现非法访问异常

    创建ExceptionTest类,在该类的main()方法中,使用反射获得String类的所有域,不要使用setAccessible方法修改这些域的可见性,然后通过反射获得私有域中与”hash”相匹配 ...

  2. CentOS下安装vsftpd

    因为FTP的端口是 两个,一个是固定21端口,还有一个任意端口的数据通道.关键是任意端口不好搞. 首先在vsftpd的配置文件中设置 任意端口的范围 [root@localhost root]# vi ...

  3. Ansible 管理任务计划

    ansible 使用 cron 模块来管理任务计划: [root@localhost ~]$ ansible 192.168.119.134 -m cron -a "name='test c ...

  4. requests 安装

    requests 是用来发送 HTTP 请求的一个库,requests 是对 urllib 和 urllib2 进行封装的一个模块,用来取代 urllib 和 urllib2,可以使用以下两种方法安装 ...

  5. 基于Elasticsearch 5.4.3的商品搜索系统

    源码已提交至http://github.com

  6. Android textview及其子类

    属性: android:autoLink设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web/email/phone/map/all) andr ...

  7. EventHandler 与常见的.Net预定义委托

    看着下面这两句事件定义及激发忽然有点不明白了, public event EventHandler<ExternalDataEventArgs> Submit; Submit(null, ...

  8. 【python3】爬取新浪的栏目分类

    目标地址: http://www.sina.com.cn/ 查看源代码,分析: 1 整个分类 在 div main-nav 里边包含 2 分组情况:1,4一组 . 2,3一组 . 5 一组 .6一组 ...

  9. LeetCode 44 Wildcard Matching(字符串匹配问题)

    题目链接:https://leetcode.com/problems/wildcard-matching/?tab=Description   '?' Matches any single chara ...

  10. [原]sublime Text2

    sublime Text2 升级到 2.0.2 build 2221 64位 的破破解 sublime Text2 download website 链接: http://pan.baidu.com/ ...