PTA 1118 Birds in Forest (25 分)【并查集】

题目

一幅画里面的鸟为同一棵树上的,问有多少棵树和多少只鸟,以及对于两只鸟判断是否在同一个树上~

输入第一行为N,接下来有N行

这N行中,第一个是这幅画(这棵树)里面的鸟的数量K,接下来是这K个鸟的编号。输出有多少棵树,多少只鸟。

接着,输入Q,表示询问的个数。

接下来的Q行,有两个鸟的编号,问你这两个鸟是不是在同一幅画(一棵树)中。

分析

躺尸很多天。。。

并查集选择使用了递归写法。


int ffind(int a)
{
    if( a != pre[a])
    {
        pre[a] = ffind(pre[a]);
    }
    return pre[a];
}

但是要注意这种写法中,

  if(exist[i]) //cout << i << " " << pre[i] << endl;
   {
         int root = ffind(i);
          cnt[root] ++;
         //cout << i << " " << root << endl;
   }

这两个地方cout的结果是不同的。递归写法需要再一次压缩路径。

代码


const int maxn = 1e4 + 10;
int pre[maxn];
int exist[maxn];
int cnt[maxn];

int ffind(int a)
{
    if( a != pre[a])
    {
        pre[a] = ffind(pre[a]);
    }
    return pre[a];
}

int main()
{
    for(int i = 0 ; i < maxn ; i ++)
        pre[i] = i;
    int N ; cin >> N;
    for(int i = 0 ; i < N ; i ++)
    {
        int K ; cin >> K;
        int st ; cin >> st; exist[st] = 1;
        for(int i = 0 ; i < K - 1 ; i ++)
        {
            int ed ; cin >> ed; exist[ed] = 1;
            int prest = ffind(st);
            int preed = ffind(ed);

            if(prest != preed)
            {
                pre[prest] = preed;
            }
        }
    }

    for(int i = 1 ; i < maxn ; i ++)
    {
            if(exist[i]) //cout << i << " " << pre[i] << endl;
            {
                int root = ffind(i);
                cnt[root] ++;
                //cout << i << " " << root << endl;
            }
    }
    int numtree = 0 , numbird = 0;
    for(int i = 1 ; i < maxn ; i ++)
    {
       if(exist[i] && cnt[i])
       {
           numtree ++;
           numbird += cnt[i];
       }
    }
    cout << numtree << " " << numbird << endl;
    int Q ; cin >> Q;
    for(int i = 0 ; i < Q ; i ++)
    {
        int a , b;
        cin >> a >> b;
        if(ffind(a) != ffind(b))
            cout << "No" << endl;
        else cout << "Yes" << endl;
    }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值