并查集代码详解附ptaL2-024部落

并查集

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。
数组实现集合操作
初始化数组为-1,对于数值,如果为负值表示为祖先节点,负值越小表示此集合节点越多,从而方便并集操作,实现高度压缩,正值为父节点

关键代码:

int myfind(int i) {			//实现查找祖先节点并缩短树高,使其子代节点向父节点集中
	if (arr[i] < 0)			//数组的初始化是祖先为自身,即节点值为下标
		return i;			//祖先为自身即返回
	return arr[i] = myfind(arr[i]);		//如果祖先不是自身,递归查找祖先,同时将当前节点和随后的父节点连接到祖先节点上,简化树
}
void join(int a, int b) {	//将ab组合加入到集合中
	int fa = myfind(a);		//拿到a和b的祖先
	int fb = myfind(b);
    int temp = arr[fa] + arr[fb];
	if (fa != fb) {			//判断ab是否为同一祖先
		if (arr[fa] < arr[fb]) {		//如果fa更小,说明此集合节点更多
			arr[fb] = fa;	//就把fb为祖先的集合连接到fa上
			arr[fa] = temp;	//更新祖先fa的节点数量
		}
		else {
			arr[fa] = fb;
			arr[fb] = temp;
		}
	}
}

例题

L2-024部落 (25分)

#include <iostream>
using namespace std;

int arr[10001];

int myfind(int i) {
	if (arr[i] < 0) {
		return i;
	}
	return arr[i] = myfind(arr[i]);
}

void join(int i, int j) {
	int fa = myfind(i);
	int fb = myfind(j);
	int temp = arr[fa] + arr[fb];
	if (fa != fb) {
		if (arr[fa] < arr[fb]) {
			arr[fb] = fa;
			arr[fa] = temp;
		}
		else {
			arr[fa] = fb;
			arr[fb] = temp;
		}
	}
}

int main() {
	for (int i = 0; i < 10001; i++) {
		arr[i] = -1;
	}
	int n;
	cin >> n;
	int sum = 0;	//sum记录节点总数
	for (int i = 0; i < n; i++) {
		int m;
		cin >> m;
		int num1, num2;		//此题只需要每组数据的第一个与其他的数据所代表的集合并集就行,所以先储存第一个数num1,num2为后续数
		for (int j = 0; j < m; j++) {
			cin >> num2;
			if (sum < num2) sum = num2;		//更新sum值求节点总数,因为由题意得最大节点表示人群数量
			if (j == 0) {
				num1 = num2;	//拿到第一个数
			}
			else {
				join(num1, num2);
			}
		}
	}

	cout << sum << " ";
	int sump = 0;
	for (int i = 1; i <= sum; i++) {	//遍历数组,节点值为负,即为祖先节点
		if (arr[i] < 0) {
			sump++;
		}
	}
	cout << sump << endl;
	int t;
	cin >> t;
	int t1, t2;
	for (int i = 0; i < t; i++) {
		cin >> t1 >> t2;
		if (myfind(t1) == myfind(t2)) {		//判断两个人是否在同一部落,判断是否为同一祖先即可
			cout << "Y" << endl;
		}
		else {
			cout << "N" << endl;
		}
	}
	return 0;
}
/*额外测试数据
5
3 10 1 2
3 3 4 5
3 1 7 8
3 9 6 4
2 1 4
2
10 5
3 7
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值