全局最小割

测试poj 2914 点从0到n-1
#define N 510
int map[N][N];
int sum[N];//记录w(A,i)
int v[N]; //给每个点装个马甲,在删点的时候用
bool visit[N];//标记是否加入了A集合
int solve(int n)
{
    int ans=1e9;
    REP(i,n)  v[i]=i;  //最开始每个马甲初始化为自身
    while(n>1)
    {
        memset(visit,0,sizeof(visit));
        memset(sum,0,sizeof(sum));  
        int k,pre=0;
        for(int i=1;i<n;i++)
        {
            k=-1;
            for(int j=1;j<n;j++)
                if(!visit[v[j]])
                {
                    sum[v[j]]+=map[v[pre]][v[j]];  
                    if(k==-1 || sum[v[k]]<sum[v[j]])  k=j; //选择出最大的w(A,v[j])
                }
            visit[v[k]]=1;//把v[k]只想的点加入A集合
                          //在循环的过程中马甲会变化,v[k]不一定是指向k的
            if(i==n-1) break;
            pre=k;
        }
        ans=min(ans,sum[v[k]]);
        if(ans==0) return 0;
        REP(j,n)    map[v[j]][v[pre]]=map[v[pre]][v[j]]+=map[v[k]][v[j]];
        v[k]=v[--n];
        //这就是这道题为什么要用马甲的地方
        //你需要删掉的是k点,并且总点数要减一
        //所以你就把马甲披在了第n-1个点上,而因为--n了,以后的循环便不会直接循环到第n-1个点
        //而是通过v[k]来访问第n-1个点,同时删掉了k点
    }
    return ans;
}

int main()
{
    int n,m,x,y,c;
    while(cin>>n>>m)
    {
        memset(map,0,sizeof(map));
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&c);
            map[x][y]+=c;
            map[y][x]+=c;
        }
        cout<<solve(n)<<endl;
    }
    return 0;
}

模板二
#include<cstdio>
#include<cstring>
#include<climits>

const int N = 501;

int n,mat[N][N],del[N],vis[N],dist[N];
int S,T;

int search(int tn){//T表征最后一个扩展进最大生成树的点,S是倒数第二个
	int i,j,tmp,max,cut;
	T=S=-1;
	memset(vis,0,sizeof(vis));
	memset(dist,0,sizeof(dist));//最大生成树
	for(i=0;i<=n-tn;i++){
		max=-1;
		for(j=0;j<n;j++){
			if(!vis[j] && !del[j] && dist[j]>max)
				max=dist[j], tmp=j;
		}
		S=T; T=tmp;
		cut=max;
		vis[T]=1;
		for(j=0;j<n;j++){
			if(!vis[j] && !del[j])
				dist[j]+=mat[T][j];
		}
	}
	return cut;
}

int Stoer_Wagner(){
	int ans=INT_MAX;
	memset(del,0,sizeof(del));
	for(int i=1;i<n;i++){//i 表征搜索次数,i越大图中剩余的点越少,自然搜索次数越少 
		int cut=search(i);
		if(cut<ans)ans=cut;
		if(ans==0)return 0;//图不连通时最小割为0
		del[T]=1;
		for(int j=0;j<n;j++){//S,T合并
			if(!del[j])mat[S][j]=mat[j][S]+=mat[T][j];
		}
	}
	return ans;
}

int main()
{
	int a,b,c,m;
	while(~scanf("%d%d",&n,&m))
	{
		memset(mat,0,sizeof(mat));
		while(m--){
			scanf("%d%d%d",&a,&b,&c);
			mat[a][b]=mat[b][a]+=c;
		}
		int ans=Stoer_Wagner();
		printf("%d\n",ans);
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值