这题有点坑,WA了我很久。
讲三点需要注意的:是否连通、是否成环、是否空树。空树的意思是存在数据0 0,对,只有两个0。但两个0是符合题目的意思的,应该输出Yes,这就有点坑了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int NN = 100000 + 5;
typedef struct point
{
int a;
struct point *p;
}point;
point t[NN];
int b[NN];
point find(point *x)//找一个点所在集合的标记点
{
if ((*x).p == NULL) return *x;//如果是根节点,则返回自己
return(find((*x).p));
}
int mer(int a, int b)
{//把两个点所在集合合并,操作是把b的根节点变成a的根节点的子节点(根节点的父节点为空)
t[find(&t[b]).a].p = &t[find(&t[a]).a];
return 1;
}
int main()
{
int n0, m0, n, m, flag;
while (cin >> n0 >> m0)
{
if (n0 == -1 && m0 == -1) break;
if (n0 == 0 && m0 == 0)
{//这里坑,空树的数据00也是符合条件的,要输出Yes
cout << "Yes" << endl;
continue;
}
memset(&t, 0, sizeof(t));
memset(b, 0, sizeof(b));
flag = 1;
t[n0].a = n0;
t[m0].a = m0;
t[m0].p = &t[n0];
b[n0] = n0;
b[m0] = m0;
while (cin >> n >> m)
{
if (!n && !m) break;
b[n] = n;
b[m] = m;
t[n].a = n;
t[m].a = m;
if (find(&t[n]).a == find(&t[m]).a)//判断输入的两个数据是否以经在同一个集合中(根节点是否相同)
{
flag = 0;
while (cin >> n >> m) if (!n && !m) break;//判断到读取的两个数据是在同一个集合中,则需要把剩下的该组数据读取完毕,跳出循环
break;
}
mer(n, m);//n和m不在同一个集合中,把n和m加到数据中
}
int bb = 0;
if(flag) //flag初时为1,如果有成环数据,则flag已变成0,不需要再判断有多少个集合
for (int i = 0; i < NN; i++)//进行检索判断是否只有一个根节点即是否只有一个集合
{
if (bb == 0 && b[i] != 0)
{
bb = find(&t[i]).a;
continue;
}
if (b[i] && find(&t[i]).a != t[bb].a)//b[i]为0表示没有数据i,判断若有数据根节点不相同,直接结束判断
{
flag = 0;
break;
}
}
if (flag) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}