【算法】并查集

写个并查集的博客,我选择用江湖门派来解释并查集程序(之前看过一个博客也是用江湖门派来解释,很通俗易懂),并查集主要分为两个步骤:寻找根节点和路径压缩。假设每个元素都是一名侠客,那么寻找根节点就是寻找掌门的过程,路径压缩就是门派合并的过程。这篇博客重在如何巧妙的理解和记忆并查集的过程,所以没有具体解释寻找根节点和路径压缩的详细过程,读者可以先大致了解一下寻找根节点和路径压缩的具体过程再来与这篇博客进行对比,这样就很容易理解并查集了。

#include<bits/stdc++.h>
using namespace std;
int pre[1000];                  //该数组存储每一名侠客,每名侠客都有自己的编号
int find(int x) {                 //找掌门 
	if (x == pre[x]) return x;    //如果x的掌门是自己,则返回自己 
	return find(pre[x]);          //如果x的掌门不是自己,就让x的上级继续找 
}
void join(int x, int y) {       //周芷若和虚竹想做朋友,但他们不是一个门派,那就把这两个门派合并成一个       
	int fx = find(x);           //找到周芷若的掌门 
	int fy = find(y);           //找到虚竹的掌门 
	if (fx != fy)               //如果两个人的掌门不是同一个人 
	  pre[fx] = fy;             //那就让周芷若的掌门当虚竹掌门的上级,两个门派合并成功 
}
int main() {
	int N, M, x, y;
	bool t[1000];
	while (cin >> N && N != 0) {
		cin >> M;
		int count = 0;
		for (int i = 1; i <= N; i++)   //初始化数组,每一个测试用例都要初始化数组 
		  pre[i] = i;
		for (int i = 1; i <= M; i++) {
		  cin >> x >> y;
		  join(x, y);
		}
		memset(t, 0, sizeof(t));
		for (int i = 1; i <= N; i++) {
			t[find(i)] = 1;
		}
		for (int i = 1; i <= N; i++) {
			if (t[i] == 1)
			  count++;
		}
		cout << count - 1 << endl;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
克鲁斯卡尔算法是一种用于求解最小生成树的贪心算法,而并查集是一种用于维护元素分组信息的数据结构。它们在解决图论问题中经常一起使用。 克鲁斯卡尔算法的基本思想是,通过不断选择边权值最小且不会产生环路的边,逐步构建最小生成树。在实现过程中,使用并查集来判断两个节点是否属于同一个连通分量,以避免形成环路。 并查集是一种用于解决集合合并与查询问题的数据结构。它通过维护一棵树来表示每个元素所属的集合,其中每个节点指向其父节点,树的根节点表示该集合的代表元素。通过路径压缩和按秩合并等优化策略,可以提高并查集的效率。 在克鲁斯卡尔算法中,首先将图中的所有边按权值从小到大排序,然后依次选择边进行判断。当选择一条边时,判断该边连接的两个节点是否属于同一个连通分量。如果不属于同一个连通分量,则选择该边,并将两个节点合并到同一个连通分量中。重复这个过程直到选择了 n-1 条边,其中 n 是图中节点的个数,即得到最小生成树。 克鲁斯卡尔算法的时间复杂度主要取决于排序边的时间复杂度,一般情况下为 O(ElogE),其中 E 是边的数量。并查集的操作时间复杂度为 O(α(n)),其中 α(n) 是一个非常慢增长的函数,可以认为是常数级别。因此,整个算法的时间复杂度为 O(ElogE)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值