求无向图的最小割
最小割集◎Stoer-Wagner算法
一个无向连通网络,去掉一个边集可以使其变成两个连通分量则这个边集就是割集;最小割集当然就权和最小的割集。
可以用最小切割最大流定理:
1.min=MAXINT,确定一个源点
2.枚举汇点
3.计算最大流,并确定当前源汇的最小割集,若比min小更新min
4.转到2直到枚举完毕
5.min即为所求输出min
不难看出复杂度很高:枚举汇点要O(n),最短增广路最大流算法求最大流是O((n^2)m)复杂度,
在复杂网络中O(m)=O(n^2),算法总复杂度 就是O(n^5);哪怕采用最高标号预进流算法求最大流O((n^2)(m^0.5)),算法总复杂度也要O(n^4)
所以用网络流算法求解最小割集复杂度不会低于O(n^4)。
---------
prim算法不仅仅可以求最小生成树,也可以求“最大生成树”。最小割集Stoer-Wagner算法就是典型的应用实例。
求解最小割集普遍采用Stoer-Wagner算法,不提供此算法证明和代码,只提供算法思路:
1.min=MAXINT,固定一个顶点P
2.从点P用类似prim的s算法扩展出“最大生成树”,记录最后扩展的顶点和最后扩展的边
3.计算最后扩展到的顶点的切割值(即与此顶点相连的所有边权和),若比min小更新min
4.合并最后扩展的那条边的两个端点为一个顶点(当然他们的边也要合并,这个好理解吧?)
5.转到2,合并N-1次后结束
6.min即为所求,输出min
prim本身复杂度是O(n^2),合并n-1次,算法复杂度即为O(n^3)
如果在prim中加堆优化,复杂度会降为O((n^2)logn)   
#include <iostream>
using namespace std;
int mat[600][600];
int res;
//Stoer-Wagner算法,加了自己看得懂的备注
//无向图全局最小割,用求prim类似方法o(n^3),学习了一个下午……
//一开始用枚举源点汇点的最大流求解,复杂度o(n^5) 超时
void Mincut(int n) {
    int node[600], dist[600];
    bool visit[600];
    int i, prev, maxj, j, k;
    for (i = 0; i < n; i++)
        node[i] = i;
    while (n > 1) {
        int maxj = 1;
        for (i = 1; i < n; i++) { //初始化到已圈集合的割大小
            dist[node[i]] = mat[node[0]][node[i]];
            if (dist[node[i]] > dist[node[maxj]])
                maxj = i;
        }
        prev = 0;
        memset(visit, false, sizeof (visit));
        visit[node[0]] = true;
        for (i = 1; i < n; i++) {
            if (i == n - 1) { //只剩最后一个没加入集合的点,更新最小割
                res = min(res, dist[node[maxj]]);
                for (k = 0; k < n; k++) //合并最后一个点以及推出它的集合中的点
                    mat[node[k]][node[prev]] = (mat[node[prev]][node[k]] += mat[node[k]][node[maxj]]);
                node[maxj] = node[--n]; //缩点后的图
            }
            visit[node[maxj]] = true;
            prev = maxj;
            maxj = -1;
            for (j = 1; j < n; j++)
                if (!visit[node[j]]) { //将上次求的maxj加入集合,合并与它相邻的边到割集
                    dist[node[j]] += mat[node[prev]][node[j]];
                    if (maxj == -1 || dist[node[maxj]] < dist[node[j]])
                        maxj = j;
                }
        }
    }
    return;
}
int main() {
    int n, m, a, b, v;
sizeof是什么
    while (scanf("%d%d", &n, &m) != EOF) {
        res = (1 << 29);
        memset(mat, 0, sizeof (mat));
        while (m--) {
            scanf("%d%d%d", &a, &b, &v);
            mat[a][b] += v;
            mat[b][a] += v;
        }
        Mincut(n);
        printf("%d\n", res);
    }
}
本文来自CSDN博客,转载请标明出处:blog.csdn/michael200892458/archive/2009/11/22/4850931.aspx
poj 2914 minimum cut 无向图全局最小割_光之龙的空间_
求无向图的最小割算法
居然比普通的最小割的复杂度还低
stoer-wagner 算法用来求无向图 g=(v, e)的全局最小割。

算法基于这样一个定理:对于任意s, t  v ∈ ,全局最小割或者等于原图的s-t 最小割,或者等于将原图进行 contract(s,
t)操作所得的图的全局最小割。

算法框架:
1. 设当前到的最小割mincut 为+∞
2. 在 g中求出任意 s-t 最小割 c,mincut = min(mincut, c) 
3. 对 g作 contract(s, t)操作,得到 g'=(v', e'),若|v'| > 1,则g=g'并转 2,否则mincut 为原图的全局最
小割

contract 操作定义:
若不存在边(p, q),则定义边(p, q)权值w(p, q) = 0
contract(a, b): 删掉点 a, b 及边(a, b),加入新节点 c,对于任意 v v ∈ ,w(v, c) = w(c, v) = w(a, v) + w(b,
v)

求 g=(v, e)中任意 s-t 最小割的算法:
定义w(a, x) = ∑w(v[i], x),v[i] a ∈
定义 ax 为在x 前加入 a 的所有点的集合(不包括 x)
1. 令集合 a={a},a为 v中任意点
2. 选取 v - a中的 w(a, x)最大的点 x加入集合 a
3. 若|a|=|v|,结束
令倒数第二个加入 a的点为 s,最后一个加入 a的点为 t,则s-t 最小割为 w(at, t)
#include <iostream>
using namespace std;
const int maxn=510;
int map[maxn][maxn];
int n;
void contract(int x,int y)
{
int i,j;
for (i=0;i<n;i++)
  if (i!=x) map[x][i]+=map[y][i],map[i][x]+=map[i][y];
for (i=y+1;i<n;i++) for (j=0;j<n;j++)
{
  map[i-1][j]=map[i][j];
  map[j][i-1]=map[j][i];
}
n--;
}
int w[maxn],c[maxn];
int sx,tx;
int mincut()
{
int i,j,k,t;
memset(c,0,sizeof(c));
c[0]=1;
for (i=0;i<n;i++) w[i]=map[0][i];
for (i=1;i+1<n;i++)
{
  t=k=-1;
  for (j=0;j<n;j++) if (c[j]==0&&w[j]>k)
    k=w[t=j];
  c[sx=t]=1;
  for (j=0;j<n;j++) w[j]+=map[t][j];
}
for (i=0;i<n;i++) if (c[i]==0) return w[tx=i];
}
int main()
{
#ifdef _debug
freopen("in.in","r",stdin);
#endif
int i,j,k,m;
while (scanf("%d%d",&n,&m)!=eof)
{
  memset(map,0,sizeof(map));
  while (m--)
  {
    scanf("%d%d%d",&i,&j,&k);
    map[i][j]+=k;
    map[j][i]+=k;
  }
  int mint=999999999;
  while (n>1)
  {
    k=mincut();
    if (k<mint) mint=k;
    contract(sx,tx);
  }
  printf("%d\n",mint);
}
return 0;
}
blog.sina/s/blog_6af663940100n532.html
【转】最小割的一点理解
(2010-10-29 16:12:28)
转载
标签:
最小割
杂谈
分类: 【Sweep---图论】
转自mjmjmtl大牛:
一、基本问题:
1.到底什么是割:原始点集为V,选出一些点集S使得sS,T=V-S,tT则S到T的边为S到T割,记做[S,T]。
2.什么是最小割:图中所有的割中,边权值和最小的割为最小割!
3.割得容量容量和流量计算的区别:割[S,T]的容量为∑(边(u,v)的容量和),其中uS,T。也就是说割的容量不计算反向的边!!而流量为正向的和反向的代数和。
4.最大流-最小割定理:最大流的值为最小割的容量!
5.怎样求割:求完最大流后,在残留网络中从source开始dfs,被染的为S,未被染的为T,则边集[S,T]为割。(或者从sink反向dfs,被染的为T,未被染的为S,边集[S,T]为割)这种思想应该没有错误,我曾经证明过,正向和反向floodFill都能得到合适的解。然而我按照逆向floodFill提交了两道special judge的题,都没有AC!分别是spoj839和poj2125(其中poj2125的SPJ有问题,一会AC一会WA),然而,对于spoj839我自己对我的逆向floodFill答案和正向floodFill答案做了对比(如果有区别,在程序中会死循环),发现二者没有区别。感觉是SPJ的问题。这一点,暂且放置,以后再次看到了再说。