ZOJ2833 并查集Disjoint Set

 一、题目指路:

https://pintia.cn/problem-sets/91827364500/exam/problems/91827366332?type=7&page=18icon-default.png?t=N7T8https://pintia.cn/problem-sets/91827364500/exam/problems/91827366332?type=7&page=18

二、并查集基础知识:

1)Disjoint Set ,意为"不相交集合"

2)并查集用于处理一些不相交集合的合并问题

3)存储结构:静态链式结构(数组)

4)并查集类的描述:

#define Maxsize 100
int parent[Maxsize];//数组
int n;//集合元素元数

//初始化操作:
for(int i=0;i<n;i++)
    parent[i]=-1; //或者:memset(parent,-1,sizeof(parent));

5)主要操作:查找算法、合并算法

//查找算法:只需要沿着节点x向上移动,直至达到parent值为-1的节点
int Find(int x)
{
    while(parent[x]>=0) x=parent[x];
    return x;
}

//合并算法:只有不同集合才可以合并,利用根节点的parent值以负数形式保存节点个数
bool Union(int i.int j)
{
    //先找到节点i,j各自的根
    int a=find(i);
    int b=find(j);
    int t=parent[a]+parent[b];//保存两个集合的总节点数
    if(a==b) return false;//相同集合,不合并
    else{
        if(parent[a]<parent[b]) //因为根节点是负数,谁小说明节点多,节点多的充当新集合的根节点
        {
            parent[b]=a;
            parent[a]=temp;
        }
        else{
            parent[a]=b;
            parent[b]=temp;
        }
    }
    return true;
}

三、解题思路:

        本题要实现“朋友的朋友是朋友”,用并查集实现集合的并。要输出某节点的朋友数,则将该节点所属的集合的根节点的parent[]值取反输出即可。

AC代码如下:考察并查集主要操作的实现

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
int N,M;
int parent[MAX];

int find(int pos)
{
	while(parent[pos]>=0) pos=parent[pos];
	return pos;
}
//不相交集合的并: 
void Union(int i,int j)
{
	if(find(i)==find(j)) return;//相同结合,不并 
	// i和 j的根并。
	int a=find(i);
	int b=find(j); 
	int temp=parent[a]+parent[b];
	if(parent[b]<parent[a])//i节点少,j多
	{
		parent[a]=b;
		parent[b]=temp;
	 } 
	 else{
	 	parent[b]=a;
		parent[a]=temp;
	 }
}
void Query(int t)
{
	while(parent[t]>0){
		t=parent[t];
	}
	cout<<endl<<-1*parent[t]; //取反输出该集合所拥有的节点个数
}
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int ans=0;
	int cnt=1;
	while(cin>>N>>M)
	{
		if(cnt>1) cout<<endl<<endl;
		++cnt;
		memset(parent,-1,sizeof(parent));//初始化
		++ans;
		cout<<"Case "<<ans<<":";
		while(M--)
		{
			char choice;
			int t1,t2,t3;
			cin>>choice;
			switch(choice)
				{
					case 'M':
						cin>>t1>>t2;
						Union(t1,t2);
						break;
					case 'Q':
						cin>>t3;
						Query(t3);
						break;
				}
		} 
	}
	return 0;
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值