IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 从零开始的数据结构:种类并查集 -> 正文阅读

[数据结构与算法]从零开始的数据结构:种类并查集

众所周知并查集可以表示一些东西是否在一个集合里。

const int N = 2e6 + 10;
int fa[N],n;
void init(){for (int i = 1; i <= n; i++)fa[i] = i; }
int find(int x) { return fa[x] == x ? x:fa[x] = find(fa[x]); }
void merge(int a, int b) {if(find(a)!=find(b))fa[find(a)] = find(b); }

上面就是并查集所有的操作了。
但是我们有些时候不仅仅是要记录一些人是否是同一个阵营,而是要去表示分别属于哪几个阵营的话,普通并查集就比较难维护了。

来看一道例题:
落谷p2024

这道题要我们维护一堆动物的两种关系
总共有三个种类 分别为克制关系,题目一开始不知道这些动物到底属于哪一类,但是先出现的话会被当做真的,如果后面的不符合前面的当做假话就不记录关系。

1.A B是否为同一类动物。
2.A是否能吃B。

可以发现第一种关系普通的并查集就可以做到,但是第二种表示两种动物的对立关系好像就很难维护。

这个时候就可以用种类并查集。

种类并查集其实就是通过扩大我们所要的空间,来建立起更多的关系。

接下来我们假设A>B>C>A;
比如在这道题里面,要表示三种对立关系的话,我们就开三倍的空间,
我们分别把 ( 1 ? ? n ) ( n + 1 ? ? 2 ? n ) ( 2 ? n + 1 ? ? 3 ? n ) (1--n)(n+1--2*n)(2*n+1--3*n) (1??n)(n+1??2?n)(2?n+1??3?n)的空间来分别表示每个动物的关系A,B,C,一开始(1,n+1,2*n+1)都表示的是第一个动物,但是我们不知道关系,所以他就可能有三种身份。

对于第一种操作:我们就把3个并查集都合并就行了,和普通并查集一样,只是要做3次。
对于第二种操作:我们把A中的x与B中的y合并就表示x能吃y,同理合并的操作也做三次。

ps:我们在判断能否合并的时候要注意,如果x吃y,又出现了y吃z,应该是z吃x了,那么x吃z就是假话。所以我们不能只判断a b是否为同一类就判错.

丑陋的画图帮助理解
n为4的时候
初始状态:
在这里插入图片描述
第一种操作:2和3连接
在这里插入图片描述
第二种操作:3吃4
在这里插入图片描述
此时我们在说4吃2的话就不行,因为4已经和克制他阵营的2在一个集合里(即2吃4)

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9 + 7;
const int MAXN = 2e5 + 10;
const int N = 5e4 + 10;
int n,m;
int fa[N*3];
int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void work() 
{
	cin>>n>>m;
	for(int i=1;i<=3*n;i++)
	{
		fa[i]=i;
	}
	int ans=0;
	while(m--)
	{
		int op,u,v;cin>>op>>u>>v;
		if(u>n||v>n)//注意特判
		{
			ans++;continue;
		}
		if(op==1)
		{
			if(find(u)==find(v+n)||find(u)==find(v+2*n))//u能吃v||v能吃u
			{
				ans++;
			}
			else
			{
				fa[find(u)]=find(v);
				fa[find(u+n)]=find(v+n);
				fa[find(u+n*2)]=find(v+2*n);
			} 
		}
		else
		{
			if(find(u)==find(v)||find(u+n)==find(v))//u,v同类||v能吃u
			{
				ans++;
			}
			else
			{
				fa[find(u)]=find(v+n);
				fa[find(u+n)]=find(v+2*n);
				fa[find(u+2*n)]=find(v);
			}
		} 
	}
	cout<<ans<<endl;
}
int main() {
	std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
	int t = 1;//忽略这里,多组样例的题用的
	//cin >> t;
	while (t--)work();
	return 0;
}

其他的例题
落谷p1525

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:33:19  更:2021-09-29 10:34:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 10:05:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码