并查集和带权并查集

这篇博客介绍了并查集的基本概念,包括find和join函数,并深入探讨了带权并查集的实现和在食物链问题中的应用。通过实例解析了如何判断和处理假话,以及提供了解题思路和AC代码。
摘要由CSDN通过智能技术生成

关于我对并查集的通俗理解:同类的为一个集合。

并查集的组成:

  1. find函数(用来查找自己的父节点)
  2. father数组(用来存储自己的父节点,千万不要忘记初始化
  3. join函数(用来压缩路径,改变自己的父节点)

 find函数:

int find(int x)
{
	if(x!=father[x])    //如果x的根节点不是本身,递归继续查找
		father[x]=find(father[x]);
	return father[x];
} 

换一种写法

int find(int x)					//查找x的父节点
{
	while(father[x] != x)	//如果x的父节点不是自己,则说明找到的人不是父节点,继续寻找
		x = father[x];				
	return x;				//找到父节点并返回
}

join函数:

void join(int x,int y)                     //把x和y合并为同一个集合
{
    int fx=find(x), fy=find(y);            //x的父节点是fx,y的父节点是fy
    if(fx != fy)                           //如果不相等,则fx是fy的父节点
        father[fx]=fy;                        
}

带权并查集

用一个数组value表示这种权值关系,注意每次value数组要清零

带权并查集的组成与并查集大致一样,但代码上有一定的差别,见代码

find函数

int find(int x)
{
	if(x==father[x])
		return x;
	int t=father[x];//t不能省,father[x]的值发生了变化 
	father[x]=find(father[x]);
	value[x]+=value[t];//value求和,权值相加 
	return father[x];
}

join函数

当出现权值这种新的联系的时候,需要把y的集合即find[y]连向x

void join(int x,int y,int s)    //s代表x与y之间的关系 
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
	{
        father[fy]=fx;    //把y的集合连向x的集合 
        value[fy]=value[x]-value[y]+s;    //符合向量的加减 
    }
}

带权并查集的典型例题——食物链

题目

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 
有人用两种说法对这N个动物所构成的食物链关系进行描述: 
第一种说法是"1 X Y",表示X和Y是同类。 
第二种说法是"2 X Y",表示X吃Y。 
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
1) 当前的话与前面的某些真的话冲突,就是假话; 
2) 当前的话中X或Y比N大,就是假话; 
3) 当前的话表示X吃X,就是假话。 
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

Input

第一行是两个整数N和K,以一个空格分隔。 
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
若D=1,则表示X和Y是同类。 
若D=2,则表示X吃Y。

Output

只有一个整数,表示假话的数目。

Sample Input

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

Sample Output

3

解题思路:

1.给了n 个动物,k行数据,每行三个整数d,x,y;d代表说法,x,y代表动物,sum代表假话数量

2.有三个物种,设置三种关系,分别是x吃y,x被y吃,x和y同一物种。然后分别用0代表同类,1代表前面吃后面,2代表前面被后面吃

3.如果x或者y比n大,或者d==2时,x==y,则直接判定为假话,sum++

4.if  d==1时,x与y相互吃的关系时,为假话,sum++;else,把关系列进去

5.if  d==2时,同类的情况为假话,sum++,else,把关系列进去

籽涵想要的AC代码

千万不要忘记初始化

#include<iostream>
#include<stdio.h>
using namespace std;
int n,k,d,x,y,sum;//sum代表假话数量 
int father[50003*3];

int find(int x)//查找 
{
	while(father[x]!=x)//父节点不为本身
		x=father[x];
	return x; 
}

void join(int a,int b)//
{
	int fa=find(a);
	int fb=find(b);
	if(fa!=fb)
		father[fa]=fb;
} 

int main()
{
//	cin >> n >> k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<n*3;i++)//初始化父节点为本身 
		father[i]=i;
	while(k--)
	{
//		cin >> d >> x >> y;
		scanf("%d%d%d",&d,&x,&y);
		if((x>n||y>n)||(d==2&&x==y))//第二种和第三种情况
		{
			sum++;
			continue;
		} 
		if(d==1)//表示X Y 同类 
		{
			if(find(x)==find(y+n)||find(y)==find(x+n))//假话,互相吃的关系 
				sum++; 
			else
			{
				join(x,y);
				join(x+n,y+n);
				join(x+2*n,y+2*n); 
			}
		}
		else if(d==2)
		{
			if(find(x)==find(y)||find(x+n)==find(y))
			//假话:1同类 2
				sum++;
			else
			{
				join(x,y+n);
				join(x+n,y+2*n);
				join(x+2*n,y);
			}
		}
	}
	printf("%d\n",sum);
//	cout << sum << endl;
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
带权并查集(Weighted Union-Find)是一种常用的数据结构,用于解决动态连通性问题。它支持两个主要操作:合并(Union)和查找(Find)。 以下是一个使用Python实现的带权并查集示例代码: ```python class WeightedUnionFind: def __init__(self, n): self.parent = list(range(n)) self.size = [1] * n self.weight = [0] * n def find(self, x): if self.parent[x] != x: self.compress_path(x) return self.parent[x] def union(self, x, y, w): root_x = self.find(x) root_y = self.find(y) if root_x == root_y: return if self.size[root_x] < self.size[root_y]: self.parent[root_x] = root_y self.weight[root_x] = w - self.weight[x] + self.weight[y] self.size[root_y] += self.size[root_x] else: self.parent[root_y] = root_x self.weight[root_y] = -w + self.weight[x] - self.weight[y] self.size[root_x] += self.size[root_y] def compress_path(self, x): if self.parent[x] != x: self.compress_path(self.parent[x]) self.weight[x] += self.weight[self.parent[x]] self.parent[x] = self.parent[self.parent[x]] def get_weight(self, x): root = self.find(x) return self.weight[x] - self.weight[root] ``` 这个实现中,`parent`列表存储每个元素的父节点索引,`size`列表存储每个元素所在集合的大小,`weight`列表存储每个元素与其父节点的权值差。 `find()`方法用于查找元素所属的集合,并进行路径压缩优化。`union()`方法用于合并两个集合,并更新权值差。`compress_path()`方法用于路径压缩,加速后续的查找操作。`get_weight()`方法用于获取元素与其根节点的权值差。 带权并查集可以在解决一些算法问题中起到很好的作用,例如最小生成树算法中的Kruskal算法。希望这个示例代码能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值