洛谷 P1892 团伙

P1892 团伙

并查集

#include<cstdio>
int fa[2500];//fa[i]表示i的朋友所在集合,fa[i+n]表示i的敌人所在集合
bool boo[2500];
int ans,n,m;
int find(int x)
{
	if(fa[x]!=x)	fa[x]=find(fa[x]);
	return fa[x];
}
void union1(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	fa[fx]=fy;
}//标准的并查集的写法
int main()
{
	int i,p,q,k;
	char c; 
	scanf("%d%d",&n,&m);
	for(i=1;i<=2*n;i++)
		fa[i]=i;//初始化,最大要初始化的是fa[n+n]即fa[2*n]
	for(i=1;i<=m;i++)
	{
		scanf("\n%c%d%d",&c,&p,&q);
		if(c=='F')
		{
			union1(p,q);
			//union1(p+n,q+n);//别搞错了,没有说朋友的敌人一定是敌人,也没有说自己的敌人与朋友的敌人一定是朋友 
		}
		if(c=='E')
		{
			union1(p,q+n);//合并p的朋友与q的敌人(q的敌人就是p的敌人的敌人) 
			union1(p+n,q);//与上面一行类似
		}
	}
	for(i=1;i<=n;i++)//判断1-n中有几个集合,每个集合一个团队时团队数量最多(合并集合只可以减少团队,而要满足题意最少也要这么多集合)
	{
		k=find(i);
		if(boo[k]==false)
		{
			boo[k]=true;
			ans++;
		}
	}
	printf("%d",ans);
	return 0;
}

### C++ B3618 寻找团伙 题解 思路 #### 问题描述 在一个小镇上,有若干个人可能属于不同的团伙。已知一些人之间的关系(朋友或敌人),现在要找出有多少个独立的团伙。 #### 解决方案概述 为了找到所有的团伙,可以采用并查集(Union-Find Set)的数据结构来处理这个问题。通过遍历每一对给出的关系,并根据这些关系更新各个节点所属集合的信息,最终统计不同连通分量的数量即可得到答案。 #### 并查集简介 并查集是一种树型数据结构,用于处理不相交集合的合并与查询操作。其主要功能包括查找某个元素所在的集合以及将两个集合合并成一个新的集合。对于本题而言,当两个人是朋友时就执行一次`union`操作;而如果是敌人则不需要任何动作因为这不会影响到当前所处的团伙划分[^1]。 #### 实现细节 下面是一个完整的程序实现: ```cpp #include <iostream> using namespace std; const int MAX_N = 1e3 + 5; int parent[MAX_N]; // 初始化函数 void init(int n){ for (int i = 0; i <= n ; ++i) { parent[i] = i; } } // 查找根结点的同时做路径压缩优化 int findRoot(int x){ if(x != parent[x]){ parent[x] = findRoot(parent[x]); } return parent[x]; } // 合并两个集合 bool unionSet(int a,int b){ int rootA=findRoot(a); int rootB=findRoot(b); if(rootA==rootB)return false; parent[rootA]=rootB; return true; } int main(){ int n,m,a,b; cin>>n>>m; init(n); //初始化parent数组 while(m--){ cin >> a >> b; unionSet(a,b); // 如果a和b是朋友,则把他们放在同一个集合里 } int count=0; for(int i=1;i<=n;++i){ if(findRoot(i)==i){ // 统计有多少个代表元(即多少个团伙) ++count; } } cout<<count<<"\n"; } ``` 此代码片段实现了上述提到的方法论,在输入部分读入人数`n`及其相互间存在的友好关联数目`m`之后,依次对每一组好友实施联合(`union`)过程直至完成全部关系解析工作。最后再利用循环计算出总共有几个独特的父级成员作为结果输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值