hdu 3367(与最大生成树无关。无关。无关。重要的事情说三遍+kruskal变形)

Pseudoforest

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2351    Accepted Submission(s): 910


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.

 

 

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.
The last test case is followed by a line containing two zeros, which means the end of the input.
 

 

Output
Output the sum of the value of the edges of the maximum pesudoforest.
 

 

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
很好的题目啊...当初错了n次
这个题目说的不是找到含有一个环的最大生成树,而是每个连通分量最多有一个环啊...所以求出最大生成树再添边的做法是错的
这个题正确的做法是每次选择合并的时候判断是否成环
先对边从大到小排序,然后进行贪心选择,如果根节点相同,则判断当前的树中是否有环,没有的话则连接两点。
如果根结点不同,如果有一棵子树有环一棵无环,则合并,然后新树标记成有环
,如果都无环,正常合并,如果都有环了,那就不合并了
 
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;

const int N = 10005;
const int M =100005;
int father[N];
int vis[N];  ///判断此树是否有环
int _find(int x){
    if(x==father[x]) return x;
    return father[x]=_find(father[x]);
}
struct Edge{
    int u,v,c;
}edge[M];
int cmp(Edge a,Edge b){
    return b.c < a.c;
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF,(n+m)){
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            father[i] = i;
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].c);
        }
        sort(edge,edge+m,cmp);///从大到小排序
        long long ans = 0;
        for(int i=0;i<m;i++){
            int x = _find(edge[i].u);
            int y = _find(edge[i].v);
            if(x==y){ ///已经是同一棵树了,判断是否该树是否存在环,不存在则可以连接两点形成环
                if(!vis[x]){
                    vis[x]=vis[y]=1;
                    ans+=edge[i].c;
                }
            }else{ ///不是同一棵树
                if(vis[x]&&vis[y]) continue; ///都存在环了不可能合并了
                if(vis[x]||vis[y]) vis[x]=vis[y]=1; ///只要两棵子树中有一棵有环,则新生成的树也是有环的
                father[x]=y;
                ans+=edge[i].c;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2016-03-28 21:50  樱花庄的龙之介大人  阅读(424)  评论(0编辑  收藏  举报