ACdream之并查集的使用

F - 娜娜梦游仙境系列——多民族王国

Time Limit:  2000/1000MS (Java/Others)     Memory Limit:  128000/64000KB (Java/Others)
Problem Description

娜娜好不容易才回忆起自己是娜娜而不是什么Alice,也回忆起了自己要继续探索这个世界的目标,便偷偷溜出皇宫。娜娜发现这个王国有很多个民族组成,每个民族都有自己的方言,更要命的是这些方面差别还很远,这就导致这个王国的人民交流十分困难。娜娜仔细观察并记录了好久,发现总共有m种不同的语言。

 

突然娜娜发现前面有一群天才在讨论问题,但是奈何语言问题,导致这群人交流非常吃力。不过幸亏的是,这群天才都有一个特殊的能力,只要消耗一个单位的能量即可完全领悟一门新的语言(妈妈再也不用担心我的四六级托福雅思GRE!)。于是娜娜久违的的好奇心又开始冒泡了,娜娜希望你告诉她,如果知道了每个人会的语言,是否能让这群天才两两直接或者间接的交流呢?所谓间接得交流是指经过若干个人的翻译使两个人得到相互表达的信息。如果不能,至少需要多少能量才能实现呢?

Input

多组数据,首先是一个正整数t(t<=20)

对于每组数据,首先是两个整数n,m(2<=n<=100,1<=m<=100),分别代表人数以及语言的种类数,语言的编号从1~m。

接下来是n行,每行对这个人进行描述

首先是一个整数k,表示这个人已经会k门语言,接下来是k个整数,分别是这个人掌握的语言编号。(0<=k<=m)

Output
对于每组数据,输出一个整数,表示使得这群人能够互相直接或者间接交流所需要的最少能量。
Sample Input
2
2 2
1 2
0
5 5
1 2
2 2 3
2 3 4
2 4 5
1 5
Sample Output
1
0
Hint

样例1中其中第一个人会第二种语言,而第二个人不会任何语言,所以只需要第二个人也学会第二种语言即可交流,所以能量数为1

样例2中有5个人,而且这5个人已经可以相互直接或间接进行交流: 1-2-3-4-5,正好构成一条链。因此不需要继续学习新的语言,能量数为0。

这题就是一个并查集的使用,并查集可以想象成是一个森林,有许多可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
int t,n,m,k;
int flag[105],lang[105],pre[105];
int find(int d)
{
    return pre[d]==d?d:(pre[d]=find(pre[d]));
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=0;i<=n;i++)
            pre[i]=i;
        memset(lang,0,sizeof(lang));
        int ff=0;
        for(int i=1;i<=n;i++)
        {
            cin>>k;
            if(k>0) ff=1;
            if(k<0) continue;
            while(k--)
            {
                int a;
                cin>>a;
                if(lang[a])
                {
                    int t1=find(lang[a]);
                    int t2=find(i);
                    if(t1>t2) swap(t1,t2);
                    pre[t1]=t2;
                }
                lang[a]=i;
            }
        }
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=n;i++)
            flag[find(i)]=1;
        int ans=0;
        for(int i=1;i<=n;i++)
            ans+=flag[i];
        if(ff)
            cout<<ans-1<<endl;
        else
            cout<<ans<<endl;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值