今天,刚学习了并查集对于并查集,也有了一定的理解了。
杭电1272这一题,主要是给你几对数,表示这两个数(可以理解为村落)直接有路,而从每一个村落到另外一个村落只能有一条路,也就是不能存在环。而并查集就是将有一定联系的村落组成一个部落(也就是集合),如果给的两个村落都存在于同一个部落,也就是存在环了。
还有一种情况就是存在两个部落,也就是有些村落到不了另一些村落。这一点,我们需要通过判断 顶点数减掉边数 是否等于,如果是,那就符合,不是,那就不符合。
也就是下面的情况:
这一题还有一个很坑的地方,输入的是0 0 ,也是符合的。
下面是AC的代码:
# include <iostream>
using namespace std;
const int Max = 100005;
int pre[Max];
bool tag[Max]; //判断有几个顶点的数组
int finds(int x) //finds函数,找到x的根节点。
{
int r = x;
while(r != pre[r])
r = pre[r];
int i = x, j;
while(i != r) //压缩路径,使集合中只有一个"老大",其他的都是“小弟”,这样查找的可以一步找到
{
j = pre[i];
pre[i] = r;
i = j;
}
return r; //返回根节点
}
int main()
{
int m, n, i;
while(cin >> m >> n)
{
for(i = 0; i < Max; i++)
{
pre[i] = i; //初始化数组
tag[i] = false; //初始化顶点数组
}
if(m == -1 && n == -1) //退出
break;
if(m == 0 && n == 0) //特殊情况
{
cout << "Yes" << endl;
continue;
}
tag[m] = true; tag[n] = true;//标记出现的顶点
int a, b, pa, pb;
int flag = 0, count = 1; //flag为是否出现环,count是数边的个数
while(cin >> a >> b)
{
if(a == 0 && b == 0)
break;
count++;
tag[a] = true; tag[b] = true; //标记顶点
pa = finds(a); //查找父节点
pb = finds(b);
if(pa != pb) //不相同,合并
pre[pa] = pb;
else //相同,存在环
{
flag = 1;
}
}
if(flag) //存在环
{
cout << "No" << endl;
continue;
}
int t = 0; //数顶点
for(i = 0; i < Max; i++)
{
if(tag[i])
t++;
}
if(t - count == 1) //判断是否存在两个集合。
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
http://blog.csdn.net/dellaserss/article/details/7724401
下面的图,或许可以更好的理解。
原文:http://blog.csdn.net/qq_25425023/article/details/44877463