该题主要考察“并查集”这一知识点。
现存问题
1、2 的算法能很容易找到反例(一个环+一个树),因为他们没有对连通性进行判断或判断不足
- 普遍没有考虑单点情况(仅单点或一个图+一个点)
测试数据的坑
HDOJ上的测试数据存在输入不完全的情况,即存在测试用例0 0都没输入就截断了
验证代码如下:
#include <bits/stdc++.h>
using namespace std;
int rudu[100005];
int count1 = 1;
void z()
{
int f = 0;
for (int i = 1; i <= 100004; i++)
{
if (rudu[i] == 0)
f++;
if (rudu[i] > 1)
f = 2;
}
if (f == 1)
printf("Case %d is a tree.\n", count1);
else
printf("Case %d is not a tree.\n", count1);
count1++;
}
int main()
{
int aa, b;
while (cin >> aa >> b)
{
if (aa == -1 && b == -1)
break;
if (aa == 0 && b == 0)
{
printf("Case %d is a tree.\n", count1);
count1++;
continue;
}
fill(rudu, rudu + 100005, -1);
rudu[aa] = 0;
rudu[b] = 0;
if (aa != b)
rudu[b]++;
while (cin >> aa >> b)
{
if (rudu[aa] == -1)
rudu[aa] = 0;
if (rudu[b] == -1)
rudu[b] = 0;
if (aa != b)
rudu[b]++;
if (aa == 0 && b == 0)
{
z();
break;
}
}
}
}
若将41行while改为:
while (1)
{
cin >> aa >> b;
则不能AC,若改为:
while (1)
{
if (!(cin >> aa >> b))
break;
则可以AC
正确代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int node[maxn]; // 节点(默认为0, 表示点不存在)
int in[maxn]; // 入度(默认为-1, 表示点不存在)
int find(int x)
{
// 启用该点, 初始化为自身
if (node[x] == 0)
{
node[x] = x;
return x;
}
while (node[x] != x)
x = node[x];
return x;
}
void merge(int a, int b)
{
a = find(a);
b = find(b);
node[a] = b;
}
int main()
{
int a, b;
int count = 1;
while (cin >> a >> b)
{
if (a == -1 && b == -1)
break;
if (a == 0 && b == 0)
{
printf("Case %d is a tree.\n", count);
count++;
continue;
}
memset(node, 0, sizeof(node));
fill(in, in + maxn, -1);
merge(a, b);
in[a] = 0;
in[b] = 0;
if (a != b)
in[b]++;
while (cin >> a >> b)
{
merge(a, b);
if (in[a] == -1)
in[a] = 0;
if (in[b] == -1)
in[b] = 0;
if (a != b)
in[b]++;
if (a == 0 && b == 0)
{
int sum = 0;
int flag = -1;
for (int i = 1; i < maxn; i++)
{
if (node[i] == i)
sum++;
if (in[i] == 0)
flag++;
if (in[i] > 1)
flag = 1;
}
if (sum == 1 && flag == 0)
printf("Case %d is a tree.\n", count);
else
printf("Case %d is not a tree.\n", count);
count++;
break;
}
}
}
}