POJ-1611(并查集 简单 套模板即可)
题目链接:http://poj.org/problem?id=1611
题目简述:
给出嫌疑犯的人数,注意他们的 编号是从0开始的。给出m组数据,每组数据的第一个数据代表这组数据的人数。文件形式输入,‘0 0’结尾,规定0号一直为嫌疑人,问有多少个嫌疑人,打印嫌疑人个数
pay attention to:
本次代码采用合并优化,和路径压缩(查询优化),但是此次的合并优化代码对于这个题目出现了新的问题。
如果两个树的高度一样,然后只有最开始的根的父节点会被改变,然后根的后代的祖先还是这个根。。如果此时恰好结束数据组的输入,那么就会出现问题。所以到最后我们仍然需要进行一次find()操作,把s[]数组化为相同的祖先即可。
具体代码如下(有优化欢迎指正):
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 3e4 + 10;
int s[maxn];
int height[maxn];
void init_set()
{
for (int i = 0; i < maxn; i++)
{
s[i] = i;
height[i] = 0;
}
}
int find_set(int x)//非递归查找算法
{
int r = x;
while (s[r] != r) r = s[r];
int i = x, j;
while (i != r)
{
j = s[i];
s[i] = r;
i = j;
}
return r;
}
//int find_set(int x)(递归查找)
//{
// if (x != s[x]) s[x] = find_set(s[x]);
// return s[x];
//}
void union_set(int x, int y)
{
x = find_set(x);
y = find_set(y);
if (height[x] == height[y])
{
height[x]++;
s[y] = x;
}
else
{
if(height[x] < height[y])
{
s[x] = y;
}
else
{
s[y] = x;
}
}
}
int main()
{
int m, n, x, y;
while (~scanf ("%d%d", &n, &m) && n)
{
init_set();
for (int i = 1; i <= m; i++)
{
int tmp;
scanf ("%d", &x);
if (x) scanf ("%d", &tmp);
for (int j = 1; j < x; j++)
{
scanf ("%d", &y);
union_set(tmp, y);
}
}
int ans = 0;
for (int i = 0; i < n; i++)
{
s[i] = find_set(i);
if (s[i] == s[0])
{
ans++;
}
}
printf ("%d\n", ans);
}
return 0;
}