小阳数数

题目描述
武林内纷乱不断,各地都自立门派,门派的人为了识别门内弟子,给了每个人一块令牌,这个令牌有

个神奇的地方,门派内的弟子的令牌不一定相同,下面是他的识别规则:

每个人的令牌都是一串数字,如果两个人的令牌有相似的地方,即有相同的数字,那就属于同一个门

派,特别的,如果两个人没有相同的数字,但是这个两个人都和另一个人有相同的数字,那么这三个

人同属一个门派,现在有一个任务,给你n个令牌,让你认出有多少个门派

例如
3
13579
2468
12

这里答案应该是1,因为第一个人和第二个人同时和第三个人有关系

输入描述:

第一行 输入一个t,代表数据组数(1<=t<=10)

第二行 输入一个n,代表n块令牌 (1<=n<=1000)

下面n行,每行一个数字序列,(1<=len<=1000)

输出描述:

有t行,每行一个数,代表有这组数据有多少个门派

示例
输入

2
3
13579
2468
12
5
12
23
34
5
5678
输出
复制

1
2

思路:并查集

其实可以利用并查集的思想,同一个并查集里的元素应具有一些共同的性质,那么对于本体来说就是

具有共同的数字了。

那么如何对两个串进行合并呢?

我们其实可以记录每个数字第一次出现在那个字符串中,字符串用编号0 - n-1表示,那么我们每输入

一个字符串,遍历这个字符串,如果这个数字之前还没有出现过,就让这个数字指向当前这个字符串

否则就可以通过之前的指向去找出两个字符串是不是在同一个并查集中,如果不在,那么就将两个并

查集合并即可

代码:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n;
char s[N];
int father[N] , f[N];

void init()
{
    memset(f , -1 , sizeof f);
    for(int i = 0 ; i < n ; ++ i) father[i] = i;
}

int find(int i)
{
    if(father[i] == i) return i;
    else return father[i] = find(father[i]);
}
int main(void)
{
    int T;
    cin >> T;
    while(T --)
    {
        scanf("%d",&n);
        
        init();//初始化函数
        
        for(int i = 0 ; i < n ; ++ i)
        {
            scanf("%s" , s);
            
            for(int j = 0 ; s[j] ; ++ j)//遍历字符串的每一个字符
            {
                int k = s[j] - '0';//得到当前的数字是多少
                
                if(f[k] == -1) f[k] = i;//如果当前的数字之前还未出现,就指向当前这个字符串
                
                else//如果出现过
                {
                    //i代表的是当前的字符串,f[k]代表的是第一次出现这个数字是哪个字符串
                    int fa = find(i) , fb = find(f[k]);
                    
                    //如果这两个并查集不是一个并查集
                    if(fa != fb)
                        father[fb] = fa;
                }
            }
        }
        
        //统计结果
        int res = 0;
        for(int i = 0 ; i < n ; ++ i)
            if(father[i] == i)
                res ++;
        printf("%d\n",res);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值