Posted on 2007-07-15 11:12
ZelluX 阅读(473)
评论(0) 编辑 收藏 所属分类:
Algorithm
突然想通了一开始一直超时的原因。
每次我都是把新的suspect并入第一个元素所在的集合中,但是由于使用了优化后的并集操作,有可能是第一个元素所在的集合并入了新的suspect所在的集合,也就是说此后last变量并没有指向第一个元素所在集合的跟结点。于是在Union方法中,parent[root1]可能得到一个正整数,并导致Find方法死循环(根结点的parent为正)
后来把Find方法放到Union方法中,问题解决了。
#include <iostream>
using namespace std;
const int DEFAULT_SIZE = 100;
class UFSets
{
private:
int *parent;
int size;
public:
UFSets(int s = DEFAULT_SIZE);
~UFSets() { delete [] parent; }
void Union(int root1, int root2);
int Find(int x);
void Clear(int n);
};
UFSets::UFSets(int s)
{
size = s;
parent = new int[size + 1];
for (int i = 0; i <= size; i++)
parent[i] = -1;
}
int UFSets::Find(int x)
{
int result = x;
while (parent[result] >= 0)
result = parent[result];
return result;
}
void UFSets::Union(int root1, int root2)
{
// The old version didn't contain the following 3 setences.
root1 = Find(root1);
root2 = Find(root2);
if (root1 == root2) return;
int temp = parent[root1] + parent[root2];
if (parent[root2] < parent[root1])
{
parent[root1] = root2;
parent[root2] = temp;
}
else
{
parent[root2] = root1;
parent[root1] = temp;
}
}
void UFSets::Clear(int n)
{
for (int i = 0; i < n; i++)
parent[i] = -1;
}
int main()
{
UFSets sets(30000);
int n, m;
while (true)
{
cin >> n >> m;
if (n == 0) break;
sets.Clear(n);
for (int i = 0; i < m; i++)
{
int t;
cin >> t;
int last, x;
cin >> last;
last = sets.Find(last);
for (int j = 1; j < t; j++)
{
cin >> x;
sets.Union(last, x);
// int temp = sets.Find(x);
// if (temp != last)
// sets.Union(last, temp);
}
}
int result = 1;
int target = sets.Find(0);
for (int i = 1; i < n; i++)
if (sets.Find(i) == target)
result ++;
cout << result << endl;
}
return 0;
}