soj 3134: windy和水星 Stoer-Wagner算法求无向图的最小割集:一个无向连通网络,去掉一个边集可以使其变成两个连通分量则这个边集就是割集;最小割集当然就权和最小的割集

Description

windy被请到了水星交通部,交通部长现在想知道水星的交通安全度为多少在水星上有n座城市,任意两座城市之间有一条权值在[1,10^5]的双向路定义:为了使得这n座城市至少有两座之间不连通,最少需要破坏的权值为安全度求水星的交通安全度

Input

输入包含多组测试数据,每组数据第一行有一个整数,n ( 2 <= n <= 100 )接下来n行,每行n个整数,除主对角线外,均为范围在[1,10^5]的整数,对角线上的权值保证为0,保证[i][j]=[j][i]

Output

每组数据输出一行,为水星的交通安全度

Sample Input

30 1 31 0 23 2 0

Sample Output

3

 //

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int MAXN = 501;

const int MAXV = 0x3F3F3F3F;

int n,m,v[MAXN],mat[MAXN][MAXN],dis[MAXN];

bool vis[MAXN];

int res;

int Stoer_Wagner(int n) {

    int res = MAXV;

    for (int i = 0;i < n;i++)

        v[i] = i;

    while (n > 1) {

        int maxp = 1,prev = 0;

        for (int i = 1;i < n;i++) {//初始化到已圈集合的割大小

            dis[v[i]] = mat[v[0]][v[i]];

            if (dis[v[i]] > dis[v[maxp]])

                maxp = i;

        }

        memset(vis,0,sizeof(vis));

        vis[v[0]] = true;

        for (int i = 1;i < n;i++) {

            if (i == n - 1) { //只剩最后一个没加入集合的点,更新最小割

                res = min(res,dis[v[maxp]]);

                for (int j = 0; j < n; j++) { //合并最后一个点以及推出它的集合中的点

                    mat[v[prev]][v[j]] += mat[v[j]][v[maxp]];

                    mat[v[j]][v[prev]] = mat[v[prev]][v[j]];

                }

                v[maxp] = v[--n];//缩点后的图

            }

            vis[v[maxp]] = true;

            prev = maxp;

            maxp = -1;

            for (int j = 1;j < n;j++)

                if (!vis[v[j]]) { //将上次求的maxp加入集合,合并与它相邻的边到割集

                    dis[v[j]] += mat[v[prev]][v[j]];

                    if (maxp == -1 || dis[v[maxp]] < dis[v[j]])

                        maxp = j;

                }

        }

    }

    return res;

}

int main() 

{

    while (scanf("%d", &n) != EOF) 

    {

        memset(mat,0,sizeof (mat));

        int x,y,z;

        int i,j;

        for(i=0;i<n;i++) 

        {

            for(j=0;j<n;j++) 

            {

                scanf("%d",&mat[i][j]);

            }

        }

        printf("%d\n",Stoer_Wagner(n));

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值