Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1844 Accepted Submission(s): 704
这道题,完全是看了别人的结题报告做的,完全没有搞懂这道题要干么.....
给出一个图,要求出最大的pseudoforest, 所谓pseudoforest就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个环, 而且这个子图的所有权值之和最大。这个就是所谓的伪森林。 过程类似与kruskal求最小生成树,千万不要直接求最大生成树,一开始时我想到的方法是用kruskal算法求出这个图的最大生成树, 然后给每一棵数再加上一条最大的边,构成一个环。 但是WA得快吐血了。 正确的做法和求最大生成树很类似,但是有一点改变, 因为每个连通分量允许有一个回环, 所以,我们可以在进行合并两颗树时,要判断这两颗树是否有回环,如果两个树都有回环,那么明显不可以合并这两颗树, 如果只有一棵树有回环,那么可以合并,然后标上记号。如果两个都没有回环,那么就直接合并了。 如果有两个点是属于同一棵树上的,那么判断这棵树上是否已有回环,如果没有的话,那么允许有一个回环,可以链接这两点,再标上记号。
代码:
1 // hdu 3367 最大生成树 2 // author: Gxjun 3 // date: 2014/11/18 4 #include<iostream> 5 #include<cstdio> 6 #include<cstring> 7 #include<cstdlib> 8 #include<algorithm> 9 using namespace std; 10 const int maxn =10005; 11 12 struct node { 13 int u,v,c; 14 bool operator < (const node &bb) const { 15 return c > bb.c; 16 } 17 }sac[maxn*10]; 18 19 int n,m; 20 int father[maxn]; 21 bool tag[maxn]; 22 23 void init() 24 { 25 for(int i=0;i<n;i++){ 26 father[i]=i; 27 } 28 } 29 30 int fin(int x){ 31 while(x!=father[x]) 32 x=father[x]; 33 return x; 34 } 35 36 bool Union(int x,int y) 37 { 38 x=fin(x); 39 y=fin(y); 40 if(x==y){ 41 if(tag[x]) return 0; 42 else{ 43 tag[x]=1; //表示已经形成环 44 return 1; 45 } 46 } 47 if(tag[x]&&tag[y]) //如果两者均形成环,这说明形成了两个环 48 return 0; 49 if(tag[x]) father[y]=x; //增大原有的环 50 else father[x]=y; 51 return 1; 52 } 53 54 int main() 55 { 56 while(~scanf("%d%d",&n,&m)&&n+m){ 57 for(int i=0 ; i<m ; i++ ){ 58 scanf(" %d %d %d ",&sac[i].u,&sac[i].v,&sac[i].c); 59 } 60 sort(sac,sac+m); 61 init(); 62 memset(tag,0,sizeof tag); 63 int ans=0; 64 for(int i=0 ; i<m ; i++) 65 { 66 if(Union(sac[i].u,sac[i].v)) 67 ans+=sac[i].c; 68 } 69 printf("%d\n",ans); 70 } 71 return 0; 72 }