7-13 部落 (25 分)

在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。

输入格式:
输入在第一行给出一个正整数N(≤10
​4
​​ ),是已知小圈子的个数。随后N行,每行按下列格式给出一个小圈子里的人:

K P[1] P[2] ⋯ P[K]

其中K是小圈子里的人数,P[i](i=1,⋯,K)是小圈子里每个人的编号。这里所有人的编号从1开始连续编号,最大编号不会超过10
​4
​​ 。

之后一行给出一个非负整数Q(≤10
​4
​​ ),是查询次数。随后Q行,每行给出一对被查询的人的编号。

输出格式:
首先在一行中输出这个社区的总人数、以及互不相交的部落的个数。随后对每一次查询,如果他们属于同一个部落,则在一行中输出Y,否则输出N。

很明显这个是并查集,我用C和C++都写了一遍。因为我C++用了set,这在C语言里是没有的。
C++实现:

//C++实现7-13 部落 (25 分)
#include <iostream>
#include <set>
using namespace std;
int t, f[100001];
int find(int x)
{
	int num = x;
	while (num != f[num])
	{
		num = f[num];
	}
	while (x != f[x])
	{
		int z = x;
		x = f[x];
		f[z] = num;
	}
	return x;
}
int main()
{
	set<int> cun;
	for (int i = 0; i <= 10000; i++)
		f[i] = i;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		int num;
		cin >> num;
		cun.insert(num);
		n--;
		int x = f[num];
		while (n--)
		{
			cin >> num;
			cun.insert(num);
			f[find(num)] = x;
		}
	}
	set<int> cun1;
	int cou = 0;
	for (set<int>::iterator it = cun.begin(); it != cun.end(); it++)
		cun1.insert(find(*it));
	cou = cun1.size();
	cout << cun.size() << " " << cou << endl;
	cin >> t;
	while (t--)
	{
		int a, b;
		cin >> a >> b;
		if (find(a) == find(b))
		{
			cout << "Y" << endl;
		}
		else
		{
			cout << "N" << endl;
		}
	}
}

C语言实现:

//C语言实现7-13 部落 (25 分)
#include <stdio.h>
#include <stdbool.h>
int t, f[100001];
int find(int x)
{
    int num = x;
    while (num != f[num])
    {
        num = f[num];
    }
    while (x != f[x])
    {
        int z = x;
        x = f[x];
        f[z] = num;
    }
    return num;
}
int main()
{
    bool pan[100001] = {false};  //判断是否有这个人
    bool pan1[100001] = {false}; //判断有几个部落
    int ch[100001];              //存储数字;
    for (int i = 0; i <= 10000; i++)
    {
        f[i] = i;
    }
    int t, cou = 0;
    scanf("%d", &t);
    while (t--)
    {
        int n, father, num;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &num);
            if (i == 0)
                father = num;
            else
            {
                f[find(num)] = father;
            }
            if (pan[num] == false)
            {
                pan[num] = true;
                ch[cou++] = num;
            }
        }
    }
    int cou1 = 0;
    for (int i = 0; i < cou; i++)
    {
        int x = find(ch[i]);
        if (pan1[x] == false)
        {
            pan1[x] = true;
            cou1++;
        }
    }
    printf("%d %d\n", cou, cou1);
    scanf("%d", &t);
    while (t--)
    {
        int a, b;
        scanf("%d %d", &a, &b);
        if (find(a) == find(b))
            printf("Y\n");
        else
            printf("N\n");
    }
    return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值