并查集之按秩合并

并查集

The Suspects
有n号人,编号0~n-1,默认0号是嫌疑人,
给出m个群组,给出每个群组的成员,每个人可以在多个群组当中,一个群组中有嫌疑人则整个群组都是嫌疑人,问共多少个嫌疑人

嫌疑人/可疑者,怎么觉得像感染者

//#include <bits/stdc++.h>
#include <iostream> 
#include <vector> 
#include <map> 
#include <algorithm> 
using namespace std;
//#define int long long
const int N=3e4+5;
int n,m;
int fa[N];
int rank[N];//按秩合并,
//本来是将元素少的集合 合并到元素多的集合,从而使得树的高度尽可能小
//这里是将编号较大的集合合并到编号较小的集合,才能使得0集合最大 
int find(int x){
	if(x==fa[x])return x;
	return fa[x]=find(fa[x]);
}
void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy){
		if(fx<fy){
			fa[fy]=fx;
			rank[fx]+=rank[fy];
		}
		else{
			fa[fx]=fy;
			rank[fy]+=rank[fx];
		}
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0); 
	while(cin>>n>>m){
		if(!m&&!n)break;
		for(int i=0;i<n;i++)fa[i]=i,rank[i]=1;
		int k,x,y;
		for(int j=0;j<m;j++){
			cin>>k>>x;
			for(int i=1;i<k;i++){
				cin>>y;
				merge(x,y);
			} 
		}
		cout<<rank[0]<<endl;
	}
	return 0;
}

访问mp[x],即使为零,mp.size()都会增一,相当于mp.insert(x,0)

太久没做并查集,一开始没想到按秩合并,于是用map容器做,过程非常离谱
且没做对
1、本来觉得mp.insert(x,y)和mp[x]=y有什么区别,并且对于累计相同值,通过mp[x]++,非常方便,
但写了下面一段发现,mp[x]一旦访问,不管是否非零,mp.size()都会增一,相当于mp.insert(x,0),这点要注意,不能用mp.size()做结果
2、cout和printf输出结果不同????!!!!!改日再看叭
3、不知道wa在哪里,还剩思维吧

//#include <bits/stdc++.h>
#include <iostream> 
#include <vector> 
#include <map> 
#include <algorithm> 
using namespace std;
//#define int long long
const int N=3e4+5;
int n,m;
map<int,int> mp;
//int fa[N];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0); 
	while(cin>>n>>m){
		if(!m&&!n)break;
		vector<vector<int> > v(m);
		v.clear();
		mp.clear();
		int k,x;
		int res=0;
		for(int i=0;i<m;i++){//m个集合 
			cin>>k;
			int f=0;
			for(int j=0;j<k;j++){
				cin>>x;//该组的学生编号
//				fa[x]=i;//每个学生可能属于不同的集合 
				v[i].push_back(x);
				if(x==0)f=1;
			}
			if(f){
				for(int l=0;l<k;l++){
					if(!mp[v[i][l]]){
						mp[v[i][l]]=1;
						res++;
					}
				}
			}
		}
		if(mp.empty()){
			cout<<"1"<<endl;
			continue;
		}
//		for(int i=0;i<n;i++){
//			if(!fa[i])continue;//说明学生i不考虑		 
//		} 
		for(int i=0;i<m;i++){
			int s=v[i].size();
			int f=0;
			for(int j=0;j<s;j++){
				if(mp[v[i][j]]){
//					res+=s;
					f=1;
					break;
				}
			}
			if(f){
				for(int j=0;j<s;j++){
					if(!mp[v[i][j]]){
						mp[v[i][j]]=1;
						res++;
					}
				}
			}
//			cout<<"naiho"<<res<<endl;
//			cout<<mp.size()<<endl;//mp[v[i][j]]莫非访问量,就会自动insert 
		}
		cout<<res<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值