首先是当年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. Dubbo -- 系统学习 笔记 -- 示例 -- 静态服务

    Dubbo -- 系统学习 笔记 -- 目录 示例 想完整的运行起来,请参见:快速启动,这里只列出各种场景的配置方式 静态服务 有时候希望人工管理服务提供者的上线和下线,此时需将注册中心标识为非动态管 ...

  2. Dubbo 实例

    POM: <!-- Dubbo --> <dependency> <groupId>com.alibaba</groupId> <artifact ...

  3. MongoDB入门知识

    基本概念 MongoDB是一个面向文档的数据库,不是关系型数据库.MongoDB是无模式的,也就是说文档的键不需要事先定义,也不会是一成不变. 跟关系数据库相比,MongoDB中出现了一些新的定义: ...

  4. ios开发之--时间格式化

    字符串转时间 iOS 中 NSDate 是时间管理类,这里获取到的时间是 UTC 时间,可以根据需要转换成任意地区的时间. NSFormatter 类是时间格式化类,可以根据指定的格式.地区将指定的时 ...

  5. ice服务初探

    http://masterkey.iteye.com/blog/182975 http://blog.csdn.net/moxiaomomo/article/details/6773979 http: ...

  6. solr java demo 基础入门

      <!--solr的maven依赖--> <dependencies> <dependency> <groupId>org.apache.solr&l ...

  7. ajax和promise的结合使用

    在需要依赖完成的ajax请求可使用promise保证执行顺序 在第一个请求正确返回后再发送第二个请求 /* 定义一个使用promise的ajax请求,这里依赖jquery 参数中请求url为必填参数 ...

  8. JAVA对URL的解码【转】

    前段时间做URL的中文转换,有些url是utf8的格式,有的是gb2312的格式,很难区分到底是utf8还是gb2312,找了好久,发现网上的一个牛人写的转换代码: package org.apach ...

  9. c语言中的内存分配malloc、alloca、calloc、malloc、free、realloc、sbr

    C语言跟内存分配方式 (1) 从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量,static变量. (2) 在栈上创建.在执行函数时,函数内局部变 ...

  10. Struts2(一)基本配置

    一.Struts2概述 1.什么是Struts2? Struts2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样使得业务逻辑控制器能够和ServletAPI脱离开来. 2.工作原理 当 ...