HDU3367+并查集应用
题意:找到一个这样的图,在这个图中,最多有一个环。
使得所有的边的和最大。
贪心+并查集
首先把边排序,然后开始分类讨论。
对于边ab(含有两个端点ab)
如果a,b是属于两个不同的集合
a b 是两个环中的点,则放弃ab
a b 有一个是环,则把环当做另一个的祖先,之后在回溯祖先的时候,能找到该点是在某个环中。
。
。
。
。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
keep moving...