并查集运用,最后那一步并查集判断个人觉得有点儿小微妙。

/*
*State: HDU3560 234MS 1812K 1260 B C++ 
*题目大意:
*        给定一个无向图,求无向图的连通分量的数量,还有连通分量是一个环的
*        数量。
*解题思路:
*        各种解法都行,用并查集比较简单。还可以用广搜,还可以用深搜,但是写起来麻烦。
*        而且广搜跟深搜的时间复杂度是O(v + e),但是并查集的时间复杂度通过有效地修改
*        可以改至接近线性,采用启发式合并还有路径压缩,还可以到达O(1),优雅至极。
*题目困惑:
*        用并查集开始写,应该是很清晰的思路的,结果因为初始化,各种TLE.怎么都没有想到
*        是因为初始化导致的TLE,白白贡献了4~5个TLE,囧。不过想不通100000的点,我初始化
*        哪里会TLE啦。以后要多注意下初始化了。多用脑袋跟时间还内存斤斤计较哈。
*/
View Code
#include <iostream>
using namespace std;

const int MAXN = 100005;

typedef struct _node
{
    int p, rank;
}N;

N uqSet[MAXN];
int vst[MAXN], du[MAXN];

void init(int n)
{
    for(int i = 0; i < n; i++)
    {
        du[i] = vst[i] = 0;
        uqSet[i].p = i;
        uqSet[i].rank = 0;
    }
}

int findSet(int x)
{
    int f = x, t;
    while(x != uqSet[x].p)
        x = uqSet[x].p;
    while(f != x)
    {
        t = uqSet[f].p;
        uqSet[f].p = x;
        f = t;
    }
    return x;
}

void Union(int x, int y)
{
    x = findSet(x);
    y = findSet(y);
    if(x == y)
        return ;
    if(uqSet[x].rank > uqSet[y].rank)
    {
        uqSet[y].p = x;
    }
    else
    {
        if(uqSet[x].rank == uqSet[y].rank)
            uqSet[y].rank++;

        uqSet[x].p = y;
    }
}

int main(void)
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt", "r", stdin);
#endif
    int n, m;
    while(scanf("%d %d", &n, &m), n || m)
    {
        init(n);
        int u, v;
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d", &u, &v);
            du[u]++, du[v]++;
            Union(u, v);
        }
        int com = 0;
        int reduce = 0;

        for(int j = 0; j < n; j++)
        {
            if(findSet(j) == j)
                com++;
            if(vst[findSet(j)] == 0 && du[j] != 2)
            {    
                vst[findSet(j)] = 1;
                reduce++;
            }
        }
        printf("%d %d\n", com, com - reduce);
    }
    return 0;
}
posted on 2012-08-16 01:32  cchun  阅读(380)  评论(0编辑  收藏  举报