7-3 部落(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

输入样例:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7

输出样例:

10 2
Y
N

代码如下:

#include <iostream>
#include<map>
#include<vector>
using namespace std;
typedef struct node
{
	int data;
	int rank;
	int parent;
}UFSTree;

void MAKE_SET(UFSTree t[], int n)
{
	int i;
	for (i = 0; i <= n; i++)
	{
		t[i].data = i;
		t[i].rank = 0;
		t[i].parent = i;
	}
}

int FIND_SET(UFSTree t[], int x)
{
	if (x != t[x].parent)
		return(FIND_SET(t, t[x].parent));
	else
		return x;
}

void UNION(UFSTree t[], int x, int y)
{
	x = FIND_SET(t, x);
	y = FIND_SET(t, y);
	if (t[x].rank > t[y].rank)
		t[y].parent = x;
	else
	{
		t[x].parent = y;
		if (t[x].rank == t[y].rank)
			t[y].rank++;
	}
}

int main() 
{
	int M,sum=0;
	cin >> M;
	UFSTree P[10001];
	map<int, int>mp;
	vector<int>vp;
	MAKE_SET(P, 10000);
	for (int i = 0; i < M; i++)
	{
		int n,M[10001];
		cin >> n >> M[0];
		if (!mp.count(M[0]))
		{
			vp.push_back(M[0]);
			mp[M[0]] = 1;
			sum++;
		}
		for (int j = 1; j < n; j++)
		{
			cin >> M[j];
			if (!mp.count(M[j]))
			{
				vp.push_back(M[j]);
				mp[M[j]] = 1;
				sum++;
			}
			UNION(P, M[j - 1], M[j]);
		}
	}

	map<int, int>team;
	int tsum = 0;
	for (int p = 0; p < vp.size(); p++)
	{
		if (!team.count(FIND_SET(P, vp[p])))
		{
			team[FIND_SET(P, vp[p])] = 1;
			tsum++;
		}
	}

	cout << sum << " " << tsum << endl;
	int N;
	cin >> N;

	for (int k = 1; k <= N; k++)
	{
		int a, b;
		cin >> a >> b;
		if (FIND_SET(P, a) == FIND_SET(P, b))
			cout << "Y" << endl;
		else
			cout << "N" << endl;
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/tobealistenner/article/details/81119403