果枫-国峰

hdu 杭电 2473 Junk-Mail Filter

题意:输入N M,N代表开始时存在N种不同的集合数从0~(N-1),M代表有M行输入。

      M X Y 代表X与Y的内容相同并在一个集合中。

      S X   代表要从X当前的集合中脱离出来成为一个独立的集合。

      最后要求的是不同集合数的个数。

      输入数据比较大,这题最好用scanf();printf()输入 输出。

解法:并查集,在集合中删除元素,用N~N+N+M作为虚拟节点。

注意:并查集,找父节点时用压缩路径的方法,本人一开始用了递归,结果不言而知的wa。

代码:

 

View Code
#include<iostream>
#include<algorithm>
using namespace std;
const int m=1400000;
int father[m],sign[m],ran[100009]; //father[]记录每一个点的父节点






int find(int x)       //压缩路径其中的奥妙自己领会
{
    int i=0;
    while(x!=father[x])
    {
        sign[i++]=x;
        x=father[x];
    }
    for(;i>0;i--)
    {
        father[sign[i-1]]=x;
    }
    return x;

}






void uion(int x,int y)
{
    x=find(x);
    y=find(y);
    if(x!=y)
        father[y]=x;
} 






int main()
{
    int n,m;
    int k=1;
    while(scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        int i;


        for(i=0;i<n;i++)    //虚拟节点的应用
        {
            father[i]=i+n;    //将0~n-1每一虚拟一个父子节点,n~n+n+m父子节点为自身,如:当n=3,m=3时
            //father[i]:3 4 5 3 4 5 6 7 8 9 
        }                    //        i:0 1 2 3 4 5 6 7 8 9
        for(i=n;i<=2*n+m;i++)
        {
            father[i]=i;
        }


        int step=2*n;      


        char c;
        int a,b;
        for(i=0;i<m;i++)
        {
            cin>>c;
            if(c=='M')
            {
                scanf("%d%d",&a,&b);
                uion(a,b);
            }
            else
            {
                scanf("%d",&a);
                father[a]=step++;
            }
        }

        for(i=0;i<n;i++)
        {
            ran[i]=find(i);
        }


        sort(ran,ran+n);


        int sum=1;
        for(i=0;i<n-1;i++)
        {
            if(ran[i]!=ran[i+1])
                sum++;
        }
        printf("Case #%d: %d\n",k++,sum);
    }
    return 0;
}

 

 

 

posted on 2012-08-31 18:47  果枫-国峰  阅读(167)  评论(0编辑  收藏  举报

导航