题目描述
在离散数学中,对等价关系和等价类的定义是:
如果集合S中的关系R是自反的、对称的和传递的,则称它为一个等价关系。
等价关系是现实世界中广泛存在的一种关系,许多应用问题可以归结至等价类问题,这类问题通常被称为等价问题。
通过使用集合,能够解决等价问题。而集合可以通过双亲表示法的树结构进行保存。通过对树结构的操作,可以实现查找、归并等操作。查找操作和归并操作的算法如下:
在以上的归并操作中,由于表示集合的树的深度与树形成的过程有关,因此在最坏情况下全部归并操作将会有O(n2)的复杂度。而通过在归并时比较子集所含成员的数目,令成员少的归并至成员多的集合,将能够提高算法的效率。下面给出优化的归并操作算法:
另外,通过增加“压缩路径”的功能,即将所有从根到相应元素路径上的元素都变成树根的孩子。算法如下所示:
本题中,将会给出n个原本互不相交的集合及k次集合合并的操作。通过这k次合并,判断最终的某两个原始的集合是否被合并成了同一个集合。
输入描述
输入的第一行包含两个用空格隔开的正整数n和k,其中n不超过100,k不超过n-1。
之后的k行中,每行包含两个用空格隔开的正整数x和y,表示将x元素所在的集合和y元素所在的集合合并至同一个集合。保证x和y均在1至n之间。
最后一行中,包含两个正整数,表示需要判断是否在同一个集合的元素编号。
输出描述
共一行,包含字符串“YES”或“NO”,“YES”表示需判断的元素在同一个集合中,“NO”表示不在同一个集合中。请注意不需要输出引号,且行尾输出换行。
输入样例
5 2
1 3
2 3
1 2
输出样例
YES
/*这题就是将每个元素的集合的根节点设为自己,然后在将题目给出的元素根节点进行合并,最后找题目要求的两个元素集合根节点是否相同
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int t[105];
int find(int a) //并查集查找根节点,并且吧路径上所有结点的根节点都变为同一个
{
int r = a;
while(t[r] != r)
{
r = t[r];
}
int i = a, j;
while(i != r)
{
j = t[i];
t[i]= r;
i = j;
}
return r;
}
void Union(int a, int b) //根节点合并
{
int x = find(a);
int y = find(b);
if(a != b)
{
t[a] = b;
}
}
int main()
{
int n, m, i, j, a, b, x, y;
while(~scanf("%d %d", &n, &m))
{
for(i = 1; i <= n; i++)
{
t[i] = i;
}
for(i = 0; i < m ; i++)
{
scanf("%d %d", &a, &b);
Union(a, b);
}
scanf("%d %d", &x, &y);
if(find(x) != find(y))
{
printf("NO\n");
}
else
{
printf("YES\n");
}
}
return 0;
}