hdu 3367 伪森林(kruskal)
http://acm.hdu.edu.cn/showproblem.php?pid=3367
求pseudoforest伪森林,要求每个连通分量最多可以有一个环。求能构成的最大值
我是用kruskal的方法按照求最大生成树那样求的,只不过要加一个判断,就是判断两颗子树是够成环,如果各成环,就不能合并,如果只有其中一个成环或者都不成环,那么就可以合并,并对其进行标记。。。
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 const int N=10010; 6 using namespace std; 7 8 int n,m; 9 int parent[N]; 10 int visited[N];//用来标记是否存在环 11 12 struct Edge { 13 int u,v,w; 14 bool operator < (const Edge &p) const { 15 return p.w<w;//从大到小 16 } 17 }edge[N*10]; 18 19 20 //初始化 21 void UFset(){ 22 for(int i=0;i<n;i++) 23 parent[i]=-1; 24 } 25 26 int Find(int x){ 27 int s; 28 for(s=x;parent[s]>=0;s=parent[s]); 29 //路径压缩,优化 30 while(s!=x){ 31 int temp=parent[x]; 32 parent[x]=s; 33 x=temp; 34 } 35 return s; 36 } 37 38 //合并 39 void Union(int R1,int R2){ 40 int r1=Find(R1); 41 int r2=Find(R2); 42 int temp=parent[r1]+parent[r2]; 43 if(parent[r1]>parent[r2]){ 44 parent[r1]=r2; 45 parent[r2]=temp; 46 }else { 47 parent[r2]=r1; 48 parent[r1]=temp; 49 } 50 } 51 52 53 int main(){ 54 while(scanf("%d%d",&n,&m)!=EOF){ 55 if(n==0&&m==0)break; 56 memset(visited,0,sizeof(visited)); 57 int u,v,ans=0; 58 for(int i=0;i<m;i++){ 59 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); 60 } 61 sort(edge,edge+m); 62 UFset(); 63 for(int i=0;i<m;i++){ 64 u=Find(edge[i].u); 65 v=Find(edge[i].v); 66 if(u!=v){ 67 if(visited[u]&&visited[v])continue; //都存在环 68 if(visited[u]||visited[v]) 69 visited[u]=visited[v]=1; 70 ans+=edge[i].w; 71 Union(u,v); 72 }else if(!visited[u]||!visited[v]){ 73 Union(u,v); 74 visited[u]=visited[v]=1; 75 ans+=edge[i].w; 76 } 77 } 78 printf("%d\n",ans); 79 } 80 return 0; 81 } 82 83