HDU 3367 Pseudoforest (克鲁斯卡尔_最大生成树:带一环)

Problem Description
In graph theory, a pseudoforest is an undirected graph in which every connected component has at most one cycle. The maximal pseudoforests of G are the pseudoforest subgraphs of G that are not contained within any larger pseudoforest of G. A pesudoforest is larger than another if and only if the total value of the edges is greater than another one’s.

 

Input
The input consists of multiple test cases. The first line of each test case contains two integers, n(0 < n <= 10000), m(0 <= m <= 100000), which are the number of the vertexes and the number of the edges. The next m lines, each line consists of three integers, u, v, c, which means there is an edge with value c (0 < c <= 10000) between u and v. You can assume that there are no loop and no multiple edges.
The last test case is followed by a line containing two zeros, which means the end of the input.
 

Output
Output the sum of the value of the edges of the maximum pesudoforest.
 

Sample Input
  
  
3 3 0 1 1 1 2 1 2 0 1 4 5 0 1 1 1 2 1 2 3 1 3 0 1 0 2 2 0 0
 

Sample Output
  
  
3 5
 

过程类似与kruskal求最小生成树,千万不要直接求最大生成树,一开始时我想到的方法是用kruskal算法求出这个图的最大生成树, 然后给每一棵数再加上一条最大的边,构成一个环。 但是WA得快吐血了。(因为可能出现重复的边)

正确的做法和求最大生成树很类似,但是有一点改变, 因为每个连通分量允许有一个回环, 所以,我们可以在进行合并两颗树时,要判断这两颗树是否有回环,如果两个树都有回环,那么明显不可以合并这两颗树, 如果只有一棵树有回环,那么可以合并,然后标上记号。如果两个都没有回环,那么就直接合并了。
如果有两个点是属于同一棵树上的,那么判断这棵树上是否已有回环,如果没有的话,那么允许有一个回环,可以链接这两点,再标上记号。

</pre><pre name="code" class="html">#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int father[11111],circle[11111];

struct node
{
	int u,v,w;
} a[111111] ;

bool cmp(node x,node y)
{
	if(x.w>y.w) return true;
	return false ;
}

int find(int x)
{
	int r=x;
	while(father[r]!=r) r=father[r];
	int i=x,j;
	while(i!=r) {
		j=father[i];
		father[i]=r;
		i=j;
	}
	return r;
}

int main()
{
	int n,m,i,j,ans;
	while(scanf("%d%d",&n,&m)!=EOF) {
		if(n==0 && m==0) break;
		for(i=0;i<n;i++) {
			father[i]=i;
			circle[i]=0;
		}
		for(i=1;i<=m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
		sort(a+1,a+1+m,cmp);
		ans=0;
		for(i=1;i<=m;i++) {
			int fx=find(a[i].u);
			int fy=find(a[i].v);
			if(fx!=fy) {
				if(circle[fx] && circle[fy]) continue;
				if(circle[fx] || circle[fy]) {
					circle[fx]=circle[fy]=1;
					father[fx]=fy;
					ans+=a[i].w;
				}
				else {
					father[fx]=fy;
					ans+=a[i].w;
				}
			}
			else if(!circle[fx]) {
				father[fx]=fy;
				circle[fx]=1;
				ans+=a[i].w;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}<span style="color:#666666;">








</span>


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值