noj1131谣言传播

 知道“人言可畏”吗?在我们的生活中,尤其在现有的网络上,存在一些广泛传播的谣言。今天我们在一个群体中研究这个问题:

(1)一个群体中存在一些两两之间的朋友关系;

(2)一个人发布“谣言”;

(3)一个人在知道“谣言”时,会告诉他(她)的朋友;

请你判断是否所有人最终都知道谣言。

第一行是一个正整数:测试用例数目,最多为100。之后,每个测试用例包括多行:

      第1行给出两个整数(空格分隔),前者表示群体人数n,后者表示“谣言”发布者t,群体成员用整数序号表示,2≤n≤200,0≤t≤n-1

       第2行给出一个整数,群体两两存在的朋友关系数m,0≤m≤20100

       m行,每行两个整数(空格分隔),表示群体中两个成员存在朋友关系。


 读完此题便易知为并查集的范畴。

  首先要思考读入的两个关系怎么并入一个集合内,我们可以采用判断他们根节点的方式,即所有数据的必定可以用他们的根节点表示,如已知1-2-3

那么我们想判断读入的1-3是否处在同一树上,只需看根节点,1的根节点为3,3的根节点是它本身3,那么自然在同一棵树上。那如何寻找他的根节点呢?

我们可以一步步向上迭代寻找每个节点的上一个节点

此部分代码如下:

 int i=x;

while(pre[i]!=i)

i=pre[i];

这样根节点i就被找到了。

 如果读入的两个数已经都在同一棵树,那么无需操作,否则就要将两个数合并,代码如下:

void mix(int x,int y)

{

int fx=Find(x);

int fy=Find(y);

if (fx!=fy)

{

pre[fx]=fy;

}

}


这样就有一个问题,我们看到我们寻找根节点是层层向上的,如果树过高势必会影响速度,该怎样处理呢?最快的查找方式自然是每一个节点的上一个节点就是根节点,所以每次查找完数据,我们就将树的高度降低,这个很有意思,代码如下:

while(r!=i)

{

j=pre[r];

pre[r]=i;

r=j;

}

return i;

} 


题外话:此题的谣言发布者除了方便理解,似乎没有其他用处,因为关键在于树的链接是否包含了所有数据,只需要保证一定有一谣言发布者即可。

附AC代码:

#include<stdio.h>
 int pre[20105];
int Find(int x)
{
    int i=x;
    int r=x;
    int j;
    while(pre[i]!=i)
    i=pre[i];
    while(r!=i)
    {
        j=pre[r];
        pre[r]=i;
        r=j;
    }
    return i;
}
void mix(int x,int y)
{
    int fx=Find(x);
    int fy=Find(y);
    if (fx!=fy)
    {
        pre[fx]=fy;
    }
}
int main()
{
    int T,t,n,m,i,a,b,temp,ok;
    scanf("%d",&T);
    while(T--)
    {   ok=1;
        scanf("%d%d",&n,&t);
        for (i=0;i<n;i++)
        pre[i]=i;
        scanf("%d",&m);
        for (i=0;i<m;i++)
        {
        scanf("%d%d",&a,&b);
        mix(a,b);
        }
        temp=Find(t);
        for (i=0;i<n;i++)
        if (Find(i)!=temp)
        {
            ok=0;
            break;
        }
        if (ok)
        printf("Yes\n");
        else
        printf("No\n");
        
    }
    return 0;
}
        


        
   


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值