算法与数据结构实验题 9.18 群聊

实验任务

在某聊天软件中,共有n个用户,m个群。如果两个用户A、B之间想要交流的话,只能通过消息链A→user1→user2→…→B进行交流,且必须满足链上相邻的两个用户在同一个群里。也就是说,如果A、B在同一个群里的话,可以直接交流。如果A、B不在同一个群里的话,也可以通过若干个中间人进行交流。

现在给出每个用户已经加入的群列表,问这n个用户总共最少还需要再加多少次群,才能使得任意两个用户之间可以进行交流。

数据输入

输入第一行为两个正整数 n(2≤n≤10000)和 m(1≤m≤100)。

接下来n行,每行第一个整数为k_i (0≤k_i≤m),表示第i个用户所加入的群数量。紧接着k_i个正整数,表示第i个用户加入的群编号(编号从1开始)。

数据输出

输出只有一个整数,表示这n个用户总共最少还需加群的次数。

输入示例

8 7
0
3 1 2 3
1 1
2 5 4
2 6 7
1 3
2 7 4
1 1

输出示例

2

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=2e9+1;

int n,m,k,x,fa[100010],ans,cnt;
vector<int>a[100010];

int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); }
void merge(int a,int b) {
	int u=find(a),v=find(b);
	if(u!=v) fa[u]=v;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=n;i++) {
		scanf("%d",&k);
		if(k==0) cnt++;
		while(k--) {
			scanf("%d",&x);
			a[x].push_back(i);
		}
	}
	for(int i=1;i<=m;i++) {
		for(int j=1;j<a[i].size();j++) {
			merge(a[i][0],a[i][j]);
		}
	}
	for(int i=1;i<=n;i++) if(find(i)==i) ans++;
	if(cnt==n) printf("%d",cnt);
	else printf("%d",ans-1);
	return 0;
}

思路

题意简要来说,就是有n个元素与m个连通集,若一个人同时在多个连通集内,那么这些连通集也互相连通,最终求连通集的数量。

那么输入这块就很显而易见了:

scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) fa[i]=i;		//并查集初始化
	for(int i=1;i<=n;i++) {
		scanf("%d",&k);
		if(k==0) cnt++;			//记下来,后面要考
		while(k--) {
		scanf("%d",&x);
		a[x].push_back(i);		//将“i”这一元素放入x群中
		}
	}

第二个要解决的问题是,怎么样确定有多少个群

可以用现实中的方式想一想,一个群总有个“群主”,对应就是并查集中的根,那么我们将一个群中所有的人“Union”在一起后,最后看看并查集数组中有多少个根,也就是“群主”之后,就可以知道有几个群了

其中,当另一个群聊中也有这个人时,在两个群聊执行全员合并时,这两个群聊相当于就合并为了一个大群聊

for(int i=1;i<=m;i++) {				//遍历所有的群
	for(int j=1;j<a[i].size();j++) {	//遍历每个群里的人
		merge(a[i][0],a[i][j]);		//同一群中的人合并
	}
}
for(int i=1;i<=n;i++) if(find(i)==i) ans++;	//找到“群主”时加一

到最后,答案应该是ans-1……吗?

if(cnt==n) printf("%d",cnt);
else printf("%d",ans-1);

这就涉及到我们读入时的操作了。正常情况下,至少有一个群聊存在,若有落单的人或群主存在,只需要一次“加群”操作即可,那么答案也就是群聊总数-1,即ans-1;但是当所有人都没有加入任何群聊时,那么ans在循环后即为人数,很明显此时没有群的存在,也就是每一个人都必须做一次“加群”操作,因此,当我们发现所有人都没加群时,输出即为人数

本题考验了我们对并查集这一数据结构的应用熟练度,以及对于题意的仔细理解

posted @ 2024-11-25 23:42  Severj  阅读(228)  评论(0)    收藏  举报