最小割算法

//最小割 Stoer-Wagner 算法		
//Etrnls 2007-4-15
//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)

//上述做法(转载)   基于两个事实(来自论文a simple and fast min-cut algorithm)

//λG= min(λG(u, v), λG/u~v).
//For each MA-order v1,...,vn of the undirected,weighted Graph G = (V, E),
//the cut({v1,...,vn−1},{vn})is a minimum vn–vn−1-cut
#include<cstdio>      //代码很难看懂的原因是代码本身不会明确的告诉你代码应用的不明显成立的定理
#include<cstring>     //代码的最初出处很难找到了
using namespace std;
const int MAX = 105;
const int INF = 1<<30;

int n, m, s, t, minCut;
int dis[MAX], map[MAX][MAX];
bool vis[MAX], set[MAX];

void search(){
    int i, j, ma, tmp;
    memset(vis, 0, sizeof(vis));
    memset(dis, 0, sizeof(dis));
    s = t = -1;
    for(i = 0; i < n; i ++){    //加入点的过程
        for(ma = -INF, j = 0; j < n; j ++){
            if(!set[j] && !vis[j] && dis[j] > ma){
                tmp = j;
                ma = dis[j];
            }
        }
        if(t == tmp) return;
        s = t, t = tmp;
        minCut = ma;
        vis[tmp] = true;
        for(j = 0; j < n;j ++){
            if(!set[j] && !vis[j])  dis[j] += map[tmp][j];
        }
    }
    return;
}

int Stoer_Wagner(){
    int i, j, ans = INF;
    memset(set, 0, sizeof(set));
    for(i = 0; i < n-1; i ++){     //缩点n-1次
        search();
        if(minCut < ans) ans = minCut;
        if(ans == 0) return 0;
        set[t] = true;          //set是被缩了的点
        for(j = 0; j < n; j ++)
            if(!set[j]){
                map[s][j] += map[t][j];
                map[j][s] += map[j][t];
            }
    }
    return ans;
}

int main(){
    int u, v ,w;
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(map, 0, sizeof(map));
        while(m --){
            scanf("%d%d%d",&u,&v,&w);
            map[u][v] += w;
            map[v][u] += w;
        }
        printf("%d\n",Stoer_Wagner());
    }
    return 0;
}
#include<cstdio>                                //上述代码的常数优化
#include<cstring>
const int N=102;
int p[N],dis[N],map[N][N];
bool vis[N];

int mincut(int n){
    int ret=0x7fffffff;
    for(int i=0;i!=n;++i)   p[i]=i;
    while(n>1){
        int t=1,s=0;
        for(int i=1;i!=n;++i){
            dis[p[i]]=map[p[0]][p[i]];
            if(dis[p[i]]>dis[p[t]]) t=i;
        }
        memset(vis,0,sizeof(vis));
        vis[p[0]]=true;
        for(int i=1;i<n;++i){
            if(i==n-1){
                if(ret>dis[p[t]]) ret=dis[p[t]];
                for(int j=0;j!=n;++j){
                    map[p[j]][p[s]]+=map[p[j]][p[t]];
                    map[p[s]][p[j]]=map[p[j]][p[s]];
                }
                p[t]=p[--n];
            }
            vis[p[t]]=true;
            s=t;t=-1;
            for(int j=1;j!=n;++j){
                if(!vis[p[j]]){
                    dis[p[j]]+=map[p[j]][p[s]];
                    if(t==-1||dis[p[j]]>dis[p[t]])  t=j;
                }
            }
        }
    }
    return ret;
}

int main(){
    int n ,m ,u, p ,w;
    while(scanf("%d%d",&n,&m)!=EOF){    //节点为0~~~~n-1
        memset(map, 0, sizeof(map));
        while(m --){
            scanf("%d%d%d",&u,&p,&w);
            map[u][p] += w;
            map[p][u] += w;
        }
        printf("%d\n",mincut(n));
    }
    return 0;
}



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值