hdu 3367 Pseudoforest(并查集)

题意:有一种叫作Pseudoforest的结构,表示在无向图上,每一个块中选取至多包含一个环的边的集合,又称“伪森林”。问这个集合中的所有边权之和最大是多少?

分析:如果没有环,那么构造的就是最大生成森林,在此基础上,只要取每个块中剩余边的最大边,必然得到结果。不过要构造出每条边归属于哪个块。

    看了别人的代码,发现原来可以直接构造出一个标记数组记录环,在做并查集的时候扩充if(find(u)==find(v))这一条件,可以直接得到结果。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 const int MAXN=11111;
 7 const int MAXM=111111;
 8 
 9 struct Edge{
10     int u,v,c;
11 }edge[MAXM];
12 
13 int p[MAXN],is[MAXN];
14 
15 int cmp(Edge a,Edge b)
16 {
17     return a.c>b.c;
18 }
19 
20 void init(int n)
21 {
22     for(int i=0;i<n;i++)
23     {
24         is[i]=0;
25         p[i]=i;
26     }
27 }
28 
29 int Find(int x)
30 {
31     return p[x]==x?x:p[x]=Find(p[x]);
32 }
33 
34 int check(int u,int v,int c)
35 {
36     int fu=Find(u);
37     int fv=Find(v);
38     if(fu==fv){
39         if(is[fu])
40             return 0;
41         is[fu]=1;
42         return 1;
43     }
44     if(is[fu]&&is[fv])
45         return 0;
46     if(is[fu])
47         p[fv]=fu;
48     else
49         p[fu]=fv;
50     return 1;
51 }
52 
53 int main()
54 {
55     int n,m;
56     while(~scanf("%d%d",&n,&m))
57     {
58         if(!n&&!m)
59             return 0;
60         for(int i=0;i<m;i++)
61             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c);
62         sort(edge,edge+m,cmp);
63 
64         int ans=0;
65         init(n);
66         for(int i=0;i<m;i++)
67         {
68             if(check(edge[i].u,edge[i].v,edge[i].c))
69                 ans+=edge[i].c;
70         }
71         printf("%d\n",ans);
72     }
73     return 0;
74 }
75 /*
76 5 6
77 0 1 4
78 1 2 5
79 0 2 3
80 0 3 2
81 3 4 3
82 3 4 2
83 */
View Code

 

posted @ 2013-10-23 15:05  Thousand Sunny  阅读(241)  评论(0编辑  收藏  举报