并查集——以nuist OJ P1648炼丹术为例
并查集
定义:并查集是一种树形的数据结构,用于处理一些不相交集合的合并及查询问题
主要构成:
并查集主要由一个整型数组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**i⩽n) 表示药材 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炼丹术为例的更多相关文章
- Leetcode之并查集专题-765. 情侣牵手(Couples Holding Hands)
Leetcode之并查集专题-765. 情侣牵手(Couples Holding Hands) N 对情侣坐在连续排列的 2N 个座位上,想要牵到对方的手. 计算最少交换座位的次数,以便每对情侣可以并 ...
- 安科 OJ 1190 连接电脑 (并查集)
时间限制:1 s 空间限制:128 M 传送门:https://oj.ahstu.cc/JudgeOnline/problem.php?id=1190 题目描述 机房里有若干台电脑,其中有一些电脑已经 ...
- 并查集练习(0743) SWUST OJ
#include<iostream> #include<cstring> using namespace std; ]; int n,m,l,ci,di; int root(i ...
- 杭电OJ——1198 Farm Irrigation (并查集)
畅通工程 Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可 ...
- 洛谷OJ P1196 银河英雄传说(带权并查集)
题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山 ...
- 九度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 ...
- 九度OJ 朋友圈 -- 并查集
题目地址:http://ac.jobdu.com/problem.php?pid=1526 题目描述: 假如已知有n个人和m对好友关系(存于数字r).如果两个人是直接或间接的好友(好友的好友的好友.. ...
- [Swust OJ 772]--Friend(并查集+map的运用)
题目链接:http://acm.swust.edu.cn/problem/772/ Time limit(ms): 1000 Memory limit(kb): 65535 Descriptio ...
- [Swust OJ 1091]--土豪我们做朋友吧(并查集,最值维护)
题目链接:http://acm.swust.edu.cn/problem/1091/ Time limit(ms): 1000 Memory limit(kb): 32768 人都有缺钱的时候,缺 ...
随机推荐
- Linux 安装jdk1.8
Linux安装jdk1.8 总结一句话就是:下载jdk1.8 ==> 解压 ==> 配置环境变量. 一. jdk的下载,这里有两种方法: 1.去Oracle官网下载. 2.jdk1.8的 ...
- Java Lambda详解
Lambda表达式是JDK 8开始后的一种新语法形式. 作用:简化匿名内部类的代码写法 简化格式 (匿名内部类被重写方法的形参列表) -> { 重写方法 } Lambda表达式只能简化函数式接口 ...
- python学习笔记(十)——进程间通信
python 在进程间通信时有很多方式,比如使用Queue的消息队列,使用 pip的管道通信,share memory 共享内存或 semaphore 信号量等通信方式. 这里我们演示一下通过消息队列 ...
- 理解feof与EOF
feof(feof msdn) feof用于判断文件结尾.头文件<cstdio>.使用方法是feof(fp),fp为指向需要判断的文件的指针.如果不到文件结尾,返回0值:如果是文件结尾,返 ...
- 前端基础问题整理-HTML相关
DOCTYPE的作用以及常见的DOCTYPE类型 <!DOCTYPE>声明位于文档中的最前面的位置,处于 <html> 标签之前,用来告知浏览器页面目前的文件是用哪种版本的HT ...
- VueJs单页应用实现微信网页授权及微信分享功能
在实际开发中,无论是做PC端.WebApp端还是微信公众号等类型的项目的时候,或多或少都会涉及到微信相关的开发,最近公司项目要求实现微信网页授权,并获取微信用户基本信息的功能及微信分享的功能,现在总算 ...
- 网络安全—xss
1.xss的攻击原理 需要了解 Http cookie ajax,Xss(cross-site scripting)攻击指的是攻击者往Web页面里插入恶意html标签或者javascript代码.比如 ...
- 给一个非矩形数组(Nonrectangular Arrays)
Nonrectangular Arrays(非矩形数组) public class Test { public static void main(String[] args) { ...
- Java 将Map按Value值降序排列
1 /** 2 * 将集合按照降序排列-FLOAT 3 * @param nowPartTwoData 4 * @return 5 */ 6 private static List<Map.En ...
- 将本地代码上传到gitLab
1. 在远程gitLab仓库创建项目, 执行下列命令 git init git remote add origin git@10.10.xxx.git (gitLab刚刚创建的工程地址) git ...