并查集

定义:并查集是一种树形的数据结构,用于处理一些不相交集合的合并及查询问题

主要构成:

并查集主要由一个整型数组pre[]和两个函数find()、join()构成。

数组pre[]记录了每个点的前驱结点是谁,函数find(x)用于查找指定结点x属于哪个集合,函数join(x,y)用于合并两个结点x和y。

作用:

并查集的主要作用是求联动分支数。

代表元:

用集合中的某个元素来代表这个集合,则该元素称为此集合的代表元

find()函数的定义与实现:

 int find(int x){
  while(pre[x]!=x) //如果代表元不是自己
  x = pre[x]; //x继续向上找其上级,直到找到代表元为止
  return x;
 }

join()函数的定义与实现:

 void join(int x,int y){
  int fx = find(x),fy=find(y);
  if(fx!=fy)
  pre[fx] = fy;
 }

路径压缩算法:将x到根节点路径上的所有点的上级都设为根节点

 //递归实现
 int find(int x){
  if(pre[x] == x) return x;
  return pre[x] = find(pre[x]);
 }
 //循环实现
 int find(int x) {
  while(x!=pre[x])x=pre[x]=pre[pre[x]];
  return x;
 }

总结:

1、用集合中的某个元素来代表这个集合,则该元素称为此集合的代表元; 2 、一个集合内的所有元素组织成以代表元为根的树形结构; 3 、对于每一个元素 x,pre[x] 存放 x 在树形结构中的父亲节点(如果 x 是根节点,则令pre[x] = x); 4 、对于查找操作,假设需要确定 x 所在的的集合,也就是确定集合的代表元。可以沿着pre[x]不断在树形结构中向上移动,直到到达根节点。 因此,基于这样的特性,并查集的主要用途有以下两点: 1、维护无向图的连通性(判断两个点是否在同一连通块内,或增加一条边后是否会产生环); 2、用在求解最小生成树的Kruskal算法里。

 //代码汇总
 const int N = 1005 //指定并查集所能包含的元素个数
 int pre[N];
 int rank[N];
 void init(int n){
  for(int i=0;i<n;i++){
  pre[i] = i;//每个节点的上一级都是自己
  rank[i] = 1;
  }
 }
 int find(int x){
  if(pre[x] == x) return x;
  return find(pre[x]);
 }
 int find(int x){
  if(pre[x] == x) return x;
  return pre[x] = find(pre[x]);
 }
 //判断两个结点是否连通
 bool isSame(int x,int y){
  return find(x) == find(y);
 }
 ​
 bool join(int x,int y){
  x = find(x);
  y = find(y);
  if(x == y) return false;
  if(rank[x] >rank[y]) pre[y] = x;
  else{
  if(rank[x] == rank[y]) rank[y]++;
  pre[x] = y;
  }
  return true;
 }

例:炼丹术

题目描述

三水最近在学习炼丹术。但是众所周知炼丹术是一门危险的学科,需要大量的调参才能保证安全。好在三水在洗衣机里面找到了一张失传已久的图纸,里面记录了若干种材料的药性。这张图纸上记录了 n种不同的药材,对于每种药材,都需要恰好一种药材来使其稳定 (这种药材可能是其自身,即这种药材本身就很稳定)。三水想知道,通过这张图纸,可以得到多少种不同的稳定的丹方。保证每种药材只会作为稳定剂出现一次。

我们认为一个丹方是从 n种药材中选择若干种 (不为 0 ),两个丹方被认为是不同的当且仅当存在一种药材在其中一个丹方中且不在另一个中。我们称一个丹方是稳定的,当且仅当所有出现在丹方中的药材的稳定剂也在药材中。

因为输出结果可能很大,所以答案对 998244353 取模。

输入描述

第一行一个数字 nn , 表示有 n (1\leqslant n\leqslant 10^6)n(1⩽n⩽106) 种不同的药材。 接下来一行 n个数字,第 i数字 a_i (1\leqslant a_i\leqslant n)a**i(1⩽a**in) 表示药材 ii 的稳定剂是 a_ia**i,保证输入是 11 到 nn 的一个全排列。

输出描述

一个整数 nn ,表示答案对 998244353 取模的结果。

样例输入
  6 2 3 4 5 6 1 
样例输出
  1
思路:
AC代码
 #include<cstdio>
 #include<iostream>
 const int MAXN=1000005;
 const int INF=0x3f3f3f3f;
 const int mod=998244353;
 ​
 using namespace std;
 ​
 int pre[MAXN], a[MAXN];
 ​
 int find(int x) {
  while(x!=pre[x])x=pre[x]=pre[pre[x]];
  return x;
 }
 int pow(int n) {
  int ans=1,base=2;
  for(int i=1;i<=n;++i) {
  ans=(ans*base)%mod;
  }
  return ans;
 }
 int main() {
  int n;
  scanf("%d",&n);
  for(int i=1;i<=n;++i) {
  scanf("%d",&a[i]);
  pre[i]=i;//初始化查数组
  }
  for(int i=1;i<=n;++i) {
  int u=find(i), v=find(a[i]);//通过前缀数组更新并查集,查询过程中进行路径压缩
  if(u!=v)pre[u]=v; //合并相关联集合
  }
  int cnt=0;
  for(int i=1;i<=n;++i) { //记录不同集合个数
  if(pre[i]==i) cnt++;
  }
  printf("%d",pow(cnt)-1);
  return 0;
 }
 

并查集——以nuist OJ P1648炼丹术为例的更多相关文章

  1. Leetcode之并查集专题-765. 情侣牵手(Couples Holding Hands)

    Leetcode之并查集专题-765. 情侣牵手(Couples Holding Hands) N 对情侣坐在连续排列的 2N 个座位上,想要牵到对方的手. 计算最少交换座位的次数,以便每对情侣可以并 ...

  2. 安科 OJ 1190 连接电脑 (并查集)

    时间限制:1 s 空间限制:128 M 传送门:https://oj.ahstu.cc/JudgeOnline/problem.php?id=1190 题目描述 机房里有若干台电脑,其中有一些电脑已经 ...

  3. 并查集练习(0743) SWUST OJ

    #include<iostream> #include<cstring> using namespace std; ]; int n,m,l,ci,di; int root(i ...

  4. 杭电OJ——1198 Farm Irrigation (并查集)

    畅通工程 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可 ...

  5. 洛谷OJ P1196 银河英雄传说(带权并查集)

    题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山 ...

  6. 九度OJ 1446 Head of a Gang -- 并查集

    题目地址:http://ac.jobdu.com/problem.php?pid=1446 题目描述: One way that the police finds the head of a gang ...

  7. 九度OJ 朋友圈 -- 并查集

    题目地址:http://ac.jobdu.com/problem.php?pid=1526 题目描述: 假如已知有n个人和m对好友关系(存于数字r).如果两个人是直接或间接的好友(好友的好友的好友.. ...

  8. [Swust OJ 772]--Friend(并查集+map的运用)

    题目链接:http://acm.swust.edu.cn/problem/772/ Time limit(ms): 1000 Memory limit(kb): 65535    Descriptio ...

  9. [Swust OJ 1091]--土豪我们做朋友吧(并查集,最值维护)

    题目链接:http://acm.swust.edu.cn/problem/1091/ Time limit(ms): 1000 Memory limit(kb): 32768   人都有缺钱的时候,缺 ...

随机推荐

  1. 详解 IOC

    什么是IOC: IOC-Inversion Of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是 ...

  2. 学习ansible(一)

    1.介绍 1 ansible基于Python开发的自动化运维工具 2 ansible基于ssh协议实现远程管理的工具,没有客户端 3 ansible软件可以实现多种批量管理操作 2.环境 主机 IP ...

  3. 学习saltstack (五)

    Saltstack介绍 Salt三种运行方式 1.local本地运行2.Master/Minion3.Salt ssh Salt的三大功能 a.远程执行b.配置管理(状态管理)c.云管理:阿里云,aw ...

  4. Netty学习摘记 —— 再谈ChannelHandler和ChannelPipeline

    本文参考 本篇文章是对<Netty In Action>一书第六章"ChannelHandler和ChannelPipeline",主要内容为ChannelHandle ...

  5. 顺利通过EMC实验(19)

  6. C++ 虚继承实现原理(虚基类表指针与虚基类表)

    虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可 ...

  7. 在linux环境下安装VMtools(成功)

    想在主机和虚拟机之间互相复制文件吗? 想更加方便的联系主机和虚拟机吗?  就安装VMtools吧 其实,在linux下安装VMtools 是非常的简单,只要简单地几步就行了! 第一步:打开虚拟机,在左 ...

  8. hive从入门到放弃(四)——分区与分桶

    今天讲讲分区表和分桶表,前面的文章还没看的可以点击链接: hive从入门到放弃(一)--初识hive hive从入门到放弃(二)--DDL数据定义 hive从入门到放弃(三)--DML数据操作 分区 ...

  9. Linux 0.11源码阅读笔记-内存管理

    内存管理 Linux内核使用段页式内存管理方式. 内存池 物理页:物理空闲内存被划分为固定大小(4k)的页 内存池:所有空闲物理页组成内存池,以页为单位进行分配回收.并通过位图记录了每个物理页是否空闲 ...

  10. vue多个数据不一样的表格导出到同一张excel里面

    刚来公司第二天, 甩了个需求, 把两个不同表格的数据 导出到同一个excel中 ........额,好吧 你要说,两个表格数据差不多, 直接合并数据导出就行: async function getDa ...