天下大乱

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/windywo/article/details/47971439

时间限制: 1 Sec
内存限制: 128 MB
提交: 132
解决: 31
[提交][状态][讨论版]

题目描述
乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。
有两种操作
1、U x y 表示x和y在同一个联盟。
2、D x 表示x退出联盟。

输入
多组测试数据
第一行两个数,n和m(1 ≤ n≤ 10^5, 1 ≤ m ≤10^5),分别表示诸侯国的个数和操作次数。
接下来有m行操作

输出
输出联盟的个数

样例输入
10 1
U 0 9
5 7
U 0 1
U 1 2
U 0 3
D 0
U 1 4
D 2
U 0 2
样例输出
9
2

刚看到这道题的时候想着so easy,删除元素时候直接写了

else if(s=='D')
{
        scanf("%d",&a);
        per[a]=a;
}

根本没想到如果删除的是根节点的话整个集合就散了。。。后来研究了别人的,说是用虚根,研究了好久终于懂

就像别人说的送便当,便当从0之n-1编号,用w数组记录存放这些便当的盒子编号,当然最初编号为几的食物就放在几号盒子中,有些是要送给同一个人的,当然就把这些合并在一起,而对于某些要退食物的,就要把该食物编号从组织中删除,删除时候用w数组将该食物放在一个新盒子中,而原来放该食物的盒子不予以处理,以免打乱他们的关系。最后寻找这些食物各自的根节点,若该根节点记录过,跳过以免重复,没有记录过便ans+1,计算总组数的数目

#include<cstdio>
#include<cstring>
int n,m,per[12],w[100020],mark[12];//w需要定义的大些,它记录的是每个数据存放的真实位置
void init()//初始化
{
    for(int i=0;i<n;i++)
    {
        per[i]=i;
        w[i]=i;
    }
}
int find(int x)//找根节点
{
    int r=x;
    while(r!=per[r])
        r=per[r];
    return r;
}
void join(int a,int b)//合并
{
    int la=find(a);
    int lb=find(b);
    if(la!=lb)
        per[la]=lb;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int ans=0,a,b,t=n;//最初的虚节点记录为n
        char s;
        init();
        while(m--)
        {
            getchar();//下面要输入字符,吸收回车键
            scanf("%c",&s);//不许再用gtchar了,整型数据能够分辨
            if(s=='U')
            {
                scanf("%d%d",&a,&b);
                join(w[a],w[b]);//不可以写作a,b,需要合并其真实的位置
            }
            else if(s=='D')
            {
                scanf("%d",&a);
                w[a]=t;//其真实位置,就像之前说的便当存放的真实盒子
                per[t]=t;//父节点变为自己
                t++;//下一个虚根
            }
        }
        memset(mark,0,sizeof(mark));
        for(int i=0;i<n;i++)
        {
            if(mark[find(w[i])]==0)//此根节点没有使用过
            {
                mark[find(w[i])]=1;//使用后记录一下
                ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/windywo/article/details/47971439