集训队第二次月考核-广播系统
题目描述
为了更加快速的传递学习任务,ACM集训队计划建设一个广播系统!按照规划,这个系统包含若干端点,这些端点由神奇的网络连接。
此网络有下述特点:
1.消息可以在任何一个端点产生,并且只能通过这个网络传递信息。每个端点接收消息后会将消息传送到与其相连的端点(单项传输,不会传输到那个消息发送过来的端点)
2.如果某个端点是产生消息的端点,那么消息将被传送到与其相连的每一个端点。
3.当消息在某个端点生成后,其余各个端点均能接收到消息
4.任意一个消息可以被快速的传给所有端点
现给你这个广播系统的连接方案,你能判断此系统是否符合以上要求并且传递给所有的端点?
输入
输入包含多组测试数据。每两组输入数据之间由空行分隔。
每组输入首先包含2个整数N和M,N(1<=N<=1000)表示端点个数,M(0<=M<=N*(N-1)/2)表示通信线路个数。
接下来M行每行输入2个整数A和B(1<=A,B<=N),表示端点A和B由神奇的网络相连。两个端点之间至多由一条网络直接相连,并且没有将某个端点与其自己相连的网络。
当N和M都为0时,输入结束。
输出
对于每组输入,如果所给的系统描述符合题目要求,则输出Yes,否则输出No。
样例输入
4 3
1 2
2 3
3 4
3 1
2 3
0 0
样例输出
Yes
No
题目分析
通过对题目的观察我们可以发现这是一个经典的并查集的题目,只需运用并查集的基本解题方法就能解出此题,只是需要注意的一点是此题是需要判断每一个端点之间是否直接或间接有联系,还有环状结构的情况。(别问我为什么当时没有做对,问就是路径压缩后查找错误…emmm…我没脑子谢谢 ),那就一起来回顾一下并查集的基础知识。
什么是并查集
概念:
并查集由一个整型数组pre[ ]和两个函数find( )、join( )构成
数组pre[ ]记录了每个点的前导点是什么,函数find(x)用于查找,函数join(x,y)用于合并
作用:
并查集的主要作用是求连通分支数(如果一个图中所有点都存在可达关系(直接或间接相连),则此图的连通分支数为1;如果此图有两大子图各自全部可达,则此图的连通分支数为2……)
总而言之:
并查集是一种树型的数据结构,用于处理一些不相加集合的合并和查询问题。
下面来一起康康代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,temp,f[10005];
//寻找根节点
int find(int x)
{
if(x!=f[x]) f[x]=find(f[x]); //压缩路径
return f[x];
}
//检查所有元素是不是同一个父亲
int check()
{
temp=find(0);
for(int i=0;i<n;i++)
{
if(find(i)!=temp)
return 0;
}
return 1;
}
int main()
{
while(cin >> n >> m)
{
if(n==0&&m==0) break;
for(int i=0;i<n;i++)
f[i]=i;
//让每一个元素的根节点是自己
for(int i=0;i<m;i++)
{
cin >> x >> y;
if(find(x)!=find(y))
f[find(x)]=find(y);
//同属一个父亲
}
if(check()&&n==m+1)
//检查每一个端点且判断是否存在环
cout <<"Yes"<<endl;
else
cout << "No"<<endl;
}
return 0;
}