题目描述
为了更加快速的传递学习任务,ACM集训队计划建设一个广播系统!按照规划,这个系统包含若干端点,这些端点由神奇的网络连接。
此网络有下述特点:
1.消息可以在任何一个端点产生,并且只能通过这个网络传递信息。每个端点接收消息后会将消息传送到与其相连的端点(单项传输,不会传输到那个消息发送过来的端点)
2.如果某个端点是产生消息的端点,那么消息将被传送到与其相连的每一个端点。
3.当消息在某个端点生成后,其余各个端点均能接收到消息
4.任意一个消息可以被快速的传给所有端点
现给你这个广播系统的连接方案,你能判断此系统是否符合以上要求并且传递给所有的端点?
Input
输入包含多组测试数据。每两组输入数据之间由空行分隔。
每组输入首先包含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时,输入结束。
Output
对于每组输入,如果所给的系统描述符合题目要求,则输出Yes,否则输出No。
sample Input
4 3
1 2
2 3
3 4
3 1
2 3
0 0
sample Output
Yes
No
心路历程
在ACM集训队的月考核中见到了这一题,一开始题目看上去好像很复杂,读完后发现好像就是一个并查集,很简单的样子 ,就很自信的开始写了,并且还在疑惑为什么题目里要给出那么多的特点。最后改了好几遍都只能过一半的样例,无奈放弃。考核完后和朋友(大佬)讨论,才发现看漏了重要条件。
解题思路
这题就是很基础的并查集,相信会并查集的各位都能很容易的写出来。根据题目中的特点1,我们发现这个网络是单向传输的,也就是如果是甲发的消息,那么甲就不能接受到这条消息。换句话说,这个系统不能有环状结构存在。所以我们不光需要判断根节点是不是只有一个,还需要判断是不是有环。受到大佬(博客名:CTGU-liyb)的点拨,发现判断是不是环,只需要判断端点的数目是不是等于线路的数目加一即可。
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e3 + 5;
int fa[N], n, m;
//初始化 fa 数组,让每个元素的根节点是自己
void init()
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
//找到一个元素的根节点
int find(int x)
{
if (x == fa[x]) return x;
else return fa[x] = find(fa[x]);//路径压缩,方便后续查找
}
//判断所有元素是不是在同一集合
bool check()
{
int root = find(1);
for (int i = 1; i <= n; i++)
{
if (find(i) != root)
return false;
}
return true;
}
int main()
{
int a, b;
while (cin >> n >> m)
{
if (n == 0 && m == 0)
break;
init();
for (int i = 0; i < m; i++)
{
cin >> a >> b;
fa[find(a)] = find(b);//将有关联的元素放在一个集合
}
if (check() && m == n - 1)//判断是否存在环状结构
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}