Problem H pseudoforest(伪森林,“最大生成树”)

时间:2021-11-15 12:35:36
Problem Description
In graph theory, a pseudoforest is an undirected graph in which every connected component has at most one cycle. The maximal pseudoforests of G are the pseudoforest subgraphs of G that are not contained within any larger pseudoforest of G. A pesudoforest is larger than another if and only if the total value of the edges is greater than another one’s.<br><br>
 

Input
The input consists of multiple test cases. The first line of each test case contains two integers, n(0 < n <= 10000), m(0 <= m <= 100000), which are the number of the vertexes and the number of the edges. The next m lines, each line consists of three integers, u, v, c, which means there is an edge with value c (0 < c <= 10000) between u and v. You can assume that there are no loop and no multiple edges.<br>The last test case is followed by a line containing two zeros, which means the end of the input.<br>
 

Output
Output the sum of the value of the edges of the maximum pesudoforest.<br>
 

Sample Input
 
 
3 3 0 1 1 1 2 1 2 0 1 4 5 0 1 1 1 2 1 2 3 1 3 0 1 0 2 2 0 0
 

Sample Output
 
 
3 5
 
============================

题意:给出一张图,求该图的最大生成树,且规定每棵树中可以并只能存在一个环。

思路:通过父节点建立一个bool数组标记该联通块是否已经有环。

AC代码:

#include<bits/stdc++.h>
using namespace std;
struct tree
{
    int l,r,v;
}a[100010];
int fat[10001];
int flag[100010];
int father(int x)
{
    if(x!=fat[x]) fat[x]=father(fat[x]);
    return fat[x];
}
void unionn(int x,int y)
{
    fat[x]=y;
}
bool cmp(tree x,tree y)
{
    return x.v>y.v;
}
int main()
{
    int n,m;
    while(cin>>n>>m&&n+m)
    {
        memset(flag,0,sizeof(flag));
        for(int i=0;i<=n;++i)fat[i]=i;
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v);
        }
        sort(a+1,a+1+m,cmp);
        int tot=0;
        for(int i=1;i<=m;++i)
        {

            int fa=father(a[i].l),fb=father(a[i].r);

            if(fa!=fb)
            {
               if(flag[fa]&&flag[fb])continue;//若两个联通块均有环,则不能将它们合并;
               tot+=a[i].v;
               //cout<<a[i].l<<" "<<a[i].r<<" "<<i<<"yi"<<endl;
               //cout<<fa<<" "<<fb<<"yi"<<endl;
               unionn(fa,fb);
               if(flag[fa]||flag[fb])//有一者已经成环,另一端也被标记;
               {
                   flag[fa]=1;
                   flag[fb]=1;
               }
            }
            else//当前两点在同一棵树中;
            {
                if(!flag[fa])//若未成环,如下操作;
                {
                    tot+=a[i].v;
                    flag[fa]=1;
                }
            }
        }
        printf("%d\n",tot);
    }
    return 0;
}


The end;