HDOJ - Is It A Tree?

HDOJ - Is It A Tree? 题解


该题主要考察“并查集”这一知识点。

现存问题

  1. 由于HDOJ上该题测试数据较弱,网上的一些答案不用并查集,只检查入度也能AC
  2. 有的答案放了并查集相关代码,但其实根本没用上(if 判断条件)

1、2 的算法能很容易找到反例(一个环+一个树),因为他们没有对连通性进行判断或判断不足

  1. 普遍没有考虑单点情况(仅单点或一个图+一个点)

测试数据的坑

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;
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值