当前位置:首页 > 题解目录 > 正文内容

【题解】团伙

亿万年的星光2周前 (06-06)题解目录17352

【题目描述】

在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足:
1、我朋友的朋友是我的朋友;
2、我敌人的敌人是我的朋友;
所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

【输入描述】

第1行为n和m,1<n<1000,1<=m<=100 000;
以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人。

【输出描述】

一个整数,表示这n个人最多可能有几个团伙。

【样例输入】

6 4
1 1 4
0 3 5
0 4 6
1 1 2

【样例输出】

3


【题目分析】


  1. 朋友的朋友是朋友(传递性)。

  2. 敌人的敌人是朋友(敌人的传递性)。

我们需要根据给定的朋友和敌人关系,将所有可能的朋友合并到同一个集合(团伙)中,最后统计集合的数量。

[解题思路]

  1. 并查集数据结构:

    • 使用并查集来维护朋友关系。

    • 每个节点的根节点代表它所属的团伙。

  2. 处理朋友关系(p=0):

    • 直接合并 x 和 y 所在的集合。

  3. 处理敌人关系(p=1):

    • 如果 x 已经有敌人,那么 y 应该和 x 的敌人是朋友。

    • 如果 y 已经有敌人,那么 x 应该和 y 的敌人是朋友。

    • 如果 x 和 y 是敌人,那么 x 的敌人集合和 y 的敌人集合需要合并。

    • 具体来说:

    • 可以用一个数组 enemy 来记录每个人的敌人。

  4. 统计团伙数量:

    • 遍历所有人,统计不同根节点的数量。


【参考答案】

#include<iostream>
using namespace std;
int rank[100],fa[100];
int enemy[100];//enemy[i]表示i的敌人 

//初始化 
void init(int n)
{
    for (int i = 1; i <= n; ++i)
    {
        fa[i] = i;
        rank[i] = 1;
    }
}
//查找 
int find(int x)
{
    if(x == fa[x])
        return x;
    else{
        fa[x] = find(fa[x]);        //父节点设为根节点
        return fa[x];         //返回父节点
    }
}

//合并 
void merge(int x,int y) {
	x=find(x);							//寻找 x的根节点 
	y=find(y);							//寻找 y的根节点 
	if(x==y) return ;					//如果 x和 y的根节点一致,说明他们共属同一集合,则不需要合并,直接返回;否则,执行下面的逻辑
	if(rank[x]>rank[y]) 				//如果 x的高度大于 y,则令 y的上级为 x
		fa[y]=x;	
	else {								
		if(rank[x]==rank[y]) 		   //如果 x的高度和 y的高度相同,则令 y的高度加1
			rank[y]++;	
		fa[x]=y;						//让 x的上级为 y
	}
}

int main(){
	int n,m;
	cin>>n>>m;
	init(n);//初始化
	for(int i=0;i<m;i++){
		int p,x,y;
		cin>>p>>x>>y;
		if(p==0){
			//如果x和y是朋友,直接合并
			merge(x,y); 
		} else{
			//x和y是敌人
			if(enemy[x]==0){
				enemy[x]=y;
			} else{
				//x的敌人是enemy[x],
				//y应该和enemy[x]是朋友
				merge(y,enemy[x]); 
			}
			
			if(enemy[y]==0){
				enemy[y]=x;
			}else{
				//y的敌人是enemy[y]
				//x 应该和 enemy[y] 是朋友
				merge(x,enemy[y]); 
			}
		}
	} 
	//统计团伙数量(不同根的数量)
	int count=0;
	for(int i=1;i<=n;i++){
		if(find(i)==i){
			count++;
		}
	} 
	cout<<count;
	return 0;
	
}


扫描二维码推送至手机访问。

版权声明:本文由青少年编程知识记录发布,如需转载请注明出处。

分享给朋友:

相关文章

【题解】奇偶校验

【题目描述】奇偶校验(Parity Check)是一种校验代码传输正确性的方法。根据被传输的一组二进制代码的数位中“1”的个数 是奇数或偶数来进行校验。采用奇数的称为奇校验,反之,称为偶校验。现在给...

【题解】均分蛋糕

【题解】均分蛋糕

【题目描述】小明的生日要到了!根据习俗,他需要将一些派分给大家。他有 N 个不同口味、不同大小的派。有 F 个朋友会来参加我的派对,每个人会拿到一块派(必须一个...

【题解】Power Strings

【题目描述】给定若干个长度 ≤106 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如:ababab 则最多有 3 个 ab 连接而成。【输入描述】输入若干行,每行有一...

分数求和

题目描述】输入n个分数并对他们求和,并用最简形式表示。所谓最简形式是指:分子分母的最大公约数为1;若最终结果的分母为1,则直接用整数表示。如: 5/6  、 10/3  均是最简形...

【题解】使每位学生都有座位的最少移动次数

【题目描述】一个房间里有 n 个 空闲 座位和 n 名 站着的 学生,房间用一个数轴表示。给你一个长度为 n&...

【题解】线段

【题目描述】在一个数轴上有n条线段,现选取其中k条线段使得这k条线段两两没有重合部分,问最大的k为多少?【输入描述】第一行为一个正整数n,下面n行每行2个数字ai,bi,描述每条线段。【输出描述】输出...