325-并查集和等价类

并查集和等价类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面的等价对,是因为一些共同的特征特点,成为等价关系(需要具体的环境)
必须有一个场景,才有等价关系
(聚合类算法,找最优)
例如,一个女生,有10个相亲对象,女生对这10个男生标号,1,2,3,…,10,0号男生有房有车,1号男生有房有车,所以0和1就等价,以此类推下去。第一次等价划分后,还可以继续细分,以身高体重颜值进行第二次等价划分,以此类推下去。

在这里插入图片描述
比如,我们有12个元素,初始化为-1,-1等负数代表是根节点。接着进行b处理,0和4等价,我们在数组的4下标位置存上0值,4的双亲在0位置,0的双亲是-2,就是树根,划分为一个等价关系。接着看,3和1等价,我们把数组下标3的位置的值置为-2,把数组下标1的位置存放3值,就是表示1的双亲在3下标,3下标的值为-2,就是根节点。以此类推下去,负数就是根节点,负数的绝对值就是代表有几个结点。
在这里插入图片描述
划分如下:
在这里插入图片描述

并查集的代码如下

#include<iostream>
using namespace std;

class UFSets
{
private:
	int* parent;
	int size;
public:
	UFSets(int sz = 12) :size(sz)//构造函数,数组值均初始为-1
	{
		parent = new int[size];
		for (int i = 0; i < size; ++i)
		{
			parent[i] = -1;
		}
	}
	~UFSets()//析构函数
	{
		delete[]parent;
		parent = nullptr;
		size = 0;
	}
	void Print(int x)
	{
		printf("%3d", x);
		for (int i = 0; i < size; ++i)
		{
			if (parent[i] == x)
			{
				Print(i);
			}
		}
	}

public:
	int Parent(int x)//寻找双亲的下标
	{
		while (parent[x] >= 0)
		{
			x = parent[x];
		}
		return x;
	}
	bool Union(int a, int b)//合并
	{
		bool res = false;
		int pa = Parent(a);
		int pb = Parent(b);
		if (pa != pb)
		{
			parent[pa] += parent[pb];
			parent[pb] = pa;
			res = true;
		}
		return res;
	}
	void Print()//打印并查集,打印分组后的数据
	{
		int num = 1;
		for (int i = 0; i < size; ++i)
		{
			if (parent[i] < 0)
			{
				printf("s%d ", num++);
				Print(i);
				printf("\n");
			}
		}
	}
};

int main()
{
	UFSets sets(12);
	sets.Union(0, 4);
	sets.Union(3, 1);
	sets.Union(6, 10);
	sets.Union(8, 9);
	sets.Union(7, 4);
	sets.Union(6, 8);
	sets.Union(3, 5);
	sets.Union(2, 11);
	sets.Union(11, 0);

	sets.Print();
	return 0;
}

运行程序
在这里插入图片描述

并查集的问题及改进

并查集的加权规则

在这里插入图片描述
上图所示导致查询的速度慢,要尽可能让树扁一些。
在这里插入图片描述
改进操作

bool Union(int a, int b)//合并
{
	bool res = false;
	int pa = Parent(a);
	int pb = Parent(b);
	if (pa != pb)
	{
		if (parent[pa] > parent[pb])
		{
			parent[pb] += parent[pa];
			parent[pa] = pb;
		}
		else
		{
			parent[pa] += parent[pb];
			parent[pb] = pa;
		}
		res = true;
	}
	return res;
}

在这里插入图片描述

并查集的折叠规则

在这里插入图片描述
在这里插入图片描述

并查集解决图的问题

克鲁斯卡尔算法
在这里插入图片描述
我们解析一下
在这里插入图片描述
在这个图,我们先把边撤销掉,剩下一个一个的顶点,我们有一个优先级队列,存放着
在这里插入图片描述
克鲁斯卡尔算法就是把这些放在堆里面。
我们有0-5,5个下标
均初始化为-1
在这里插入图片描述
0-2是第一小的,我们从堆里面取出来,0和2下标是-1,我们把0下标置为-2,2下标置为0,0和2连为一个边。
在这里插入图片描述

第二小是3-5,3和5下标是-1,3下标的值置为-2,5下标的值置为3。
在这里插入图片描述
第三小是1-4,等于3,1下标和4下标是-1,我们把1下标置为-2,4下标置为3。
在这里插入图片描述
第四小是2-5,2下标值是0,0下标的值为-2,5下标值是3,3下标的值为-2,不在一个集合中,把0下标的值置为-4,3下标的值置为0。
在这里插入图片描述
接下来如果选0-3,就是环了,要舍弃。如果要2-3,是在同一个集合中,也是带环,舍弃。如果选1-2,1是-2,2是0,0下标值等于-4,我们就把0下标值改为-6,把1下标的值置为0。
在这里插入图片描述

如何判断图是不是来连通的?

如果只有1个集合,就是连通的,如果多于1个集合,图就不是连通的!

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值