HDU3367+并查集应用

题意:找到一个这样的图,在这个图中,最多有一个环。

使得所有的边的和最大。

 

贪心+并查集

首先把边排序,然后开始分类讨论。

对于边ab(含有两个端点ab)

如果a,b是属于两个不同的集合

      a b 是两个环中的点,则放弃ab

      a b 有一个是环,则把环当做另一个的祖先,之后在回溯祖先的时候,能找到该点是在某个环中。

 1 /*
 2 找到一个图,使得每一个连通分量最多有一个环
 3 */
 4 #include<stdio.h>
 5 #include<string.h>
 6 #include<stdlib.h>
 7 #include<algorithm>
 8 using namespace std;
 9 const int maxn = 10005;
10 const int maxm = 100005;
11 struct node{
12     int u,v,val;
13 }edge[ maxm ];
14 int fa[ maxn ],circle[ maxn ];
15 int find( int x ){
16     if( fa[x]==x ) return x;
17     fa[x] = find(fa[x]);
18     return fa[x];
19 }
20 bool union_ab( int x,int y ){
21     int fax = find(x);
22     int fay = find(y);
23     if( fax==fay ){
24         if( circle[ fax ]==-1 ){
25             circle[ fax ] = 1;
26             return true;
27         }//形成一个环
28         return false;
29         //已经是环
30     }
31     else{
32         if( circle[ fax ]==circle[ fay ]&&circle[ fax ]==1 )
33             return false;
34         if( circle[ fax ]==1 )
35             fa[ fay ] = fax;
36         else
37             fa[ fax ] = fay;
38         //这里注意把环作为祖先,因为find
39         return true;
40     }
41 }
42 void init( int n ){
43     for( int i=0;i<n;i++ ){
44         fa[i] = i;
45         circle[ i ] = -1;
46     }
47 }
48 int cmp( node a,node b ){
49     return a.val>b.val;
50 }
51 int main(){
52     int n,m;
53     while( scanf("%d%d",&n,&m)==2,n||m ){
54         //if( n==0&&m==0 ) break;
55         for( int i=0;i<m;i++ )
56             scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].val);
57         init( n );
58         sort( edge,edge+m,cmp );
59         int ans = 0;
60         for( int i=0;i<m;i++ ){
61             if( union_ab( edge[i].u,edge[i].v) )
62                 ans += edge[i].val;
63         }
64         printf("%d\n",ans);
65     }
66     return 0;
67 }
View Code

 

posted @ 2013-07-07 16:46  xxx0624  阅读(424)  评论(0编辑  收藏  举报