【并查集-判环】Is It A Tree? POJ - 1308
Is It A Tree? POJ - 1308
小希的迷宫 HDU - 1272
题意:
这两题几乎一样,代码改一下输出就行了。
给定一个图,判断这个图是不是树。
思路:
这里判定标准有三个:一是无环,二是n个结点,n-1条边,三是空树的情况。
后两个条件很简单,统计一下就可以了;至于判环,可以用到并查集。
将存在通路(直接或间接)的结点\(u\)与\(v\)视为在同一个集合内,则可以将一条边的两个端点并在一起。如存在边\(0→1\)及边\(1→2\),则\(0\)、\(1\)、\(2\)并入同一个集合,然后再有边\(0→2\),又\(0\)、\(2\)已经属于同一集合,也就是说,加入这条边之后会构成回路,即当find(u)==find(v)
时,图中存在环。
int fa[maxn];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
fa[x] = y;
//因为在merge函数之前已经find过并比较了,以下均可省略
/*
int fx = find(x);
int fy = find(y);
if (fx != fy) fa[fy] = fx;
*/
}
int main()
{
//ios::sync_with_stdio(false);
int n, m;
int kase = 0;
int ok = 1;
int edge = 0;
set<int> s;
for (int i = 1; i < maxn; i++) fa[i] = i;
while (cin >> n >> m) {
if (n == -1 && m == -1) break;
if (!(!n && !m)) {
s.insert(n);
s.insert(m);
edge++;
if (find(n) == find(m)) ok = 0;
else merge(n, m);
}
else {
if ((edge != 0 && edge != s.size() - 1) || !ok) {
cout << "Case " << ++kase << " is not a tree." << endl;
}
else {
cout << "Case " << ++kase << " is a tree." << endl;
}
edge = 0;
ok = 1;
s.clear();
for (int i = 1; i < maxn; i++) fa[i] = i;
}
}
return 0;
}