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 */