电子学会六级-数据结构-并查集
并查集
https://www.luogu.com.cn/problem/P3367
//https://blog.csdn.net/qq_43345339/article/details/105151512
#include<bits/stdc++.h>
using namespace std;
const int maxn=10005;
int f[maxn];//存储父节点编号
/*
输入:
N个元素M个操作
接下来M行 每行 z x y
z表示操作 1 将x y合并一个集合 2输出 x y是否在一个集合内 是输出 y 否则输出 x
输出: z=2时 操作对应输出
输入样例:
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
输出样例:
N
Y
N
Y
说明:
4 7
2 1 2 1 2是否在一个集合 N --1的根为1 2的根为2 不同集合
1 1 2 1 2合并一个集合 1为根
2 1 2 1 2是否在一个集合 Y --1的根为1 2的根为1 相同集合
1 3 4 3 4合并一个集合 3为根
2 1 4 1 4是否在一个集合 N --1的根为1 3的根为3 不同集合
1 2 3 2 3合并一个集合 2的根为1 3的根为3 则把1 2为根的两个集合合并 1 2 3 4一个集合 根为1
2 1 4 1 4 是否在一个集合 Y --1的根为1 4的根为1 相同集合
找根的过程
如果父节点和当前节点不同 则不是根
使用如节点找根
例如:
f[1]=1
f[2]=1
find(2)-->find(1) --return 1
f[1]=1
f[2]=1
f[3]=2
find(3)-->find(2)-->find(1) --return 1
*/
int find(int x){
if(f[x]==x){//如果当前节点是根 返回根 --父节点是自己 就是根节点
return x;
}else{
return find(f[x]);//否则递归从父节点找根
}
}
//查找x节点的根节点
/*
f[1]=1
f[2]=1
f[3]=2
find(3)-->find(2)-->find(1) --return 1
f[3]=1 f[2]=1
find(3)-->find(1)-- return 1
*/
int find1(int x){
//如果父节点不是自己 说明当前节点不是根 必然存在父节点
//找父节点的根 父节点设置为根 缩短到根的深度 路径压缩 --直接挂在根下面
if(f[x]!=x) f[x]=find1(f[x]);
return f[x];//返回根
}
int main(){
int n,m;//n个元素 m次操作
cin>>n>>m;//输入
for(int i=1;i<=n;i++){//初始化 单独一个集合 根初始化为自己
f[i]=i;
}
for(int i=1;i<=m;i++){
int z,x,y;//z对x y操作 z=1 x y合并 z=2 输出x y是否在一个集合
cin>>z>>x>>y;//输入
int rx=find(x);//找x所在集合的根
int ry=find(y);//找y所在集合的根
if(z==1){//合并 x y
if(rx!=ry){//根不同 即不在一个集合 合并集合
f[rx]=ry;//x所在集合 指向y所在集合的根 f[ry]=rx 也可以
}
}else{//判断 x y是否在一个集合
if(rx==ry){//根相同 x y在一个集合
cout<<"Y"<<endl;
}else{//根不同 x y不在一个集合
cout<<"N"<<endl;
}
}
}
return 0;
}
修复公路
https://www.luogu.com.cn/problem/P1111
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,m;
int f[maxn];
struct node{
int x,y,t;//从x村庄到y村庄 在t时刻可以修好
friend bool operator < (node node1,node node2){//重写<运算符 friend 允许外部sort访问此函数
return node1.t<node2.t;//按t从小到大排序
}
}e[maxn];//声明e结构体数组 存储边 边集数组
//找根
int find(int x){
//父节点不是自己 说明不是根
//不是根一定会有父节点 自己和父节点具体相同的根 可以通过父节点找根
//找到根后 赋值给父节点 即自己父亲时根 自己挂在根下面
if(f[x]!=x) f[x]=find(f[x]);//路径压缩找根
return f[x];//返回根
}
int main(){
cin>>n>>m;//输入n个村庄 m条路
for(int i=1;i<=m;i++){
f[i]=i;//父节点指向自己 每个节点都是根 每个节点单独一棵树
cin>>e[i].x>>e[i].y>>e[i].t;//输入每条边
}
sort(e+1,e+m+1);//对所有路 按修完时刻t排序 升序 贪心 先修完成早的 修完最后一条的t时刻正好修完
// for(int i=1;i<=m;i++){
// cout<<e[i].t<<endl;
// }
for(int i=1;i<=m;i++){//循环边 并查集
int rx=find(e[i].x);//找x的根rx
int ry=find(e[i].y);//找y的根ry
if(rx!=ry){//x和y根不同 属于不同集合
f[rx]=ry;//集合合并 修好一条路
n--;// 待修路-1
if(n==1){//都在一个集合时 路都连通了
cout<<e[i].t;//输出修好最后一条路的时间
return 0;
}
}
}
cout<<-1;//不能完全连通 输出-1
return 0;
}
朋友
https://www.luogu.com.cn/problem/P2078
口袋的天空
https://www.luogu.com.cn/problem/P1195
家谱
https://www.luogu.com.cn/problem/P2814
营救
https://www.luogu.com.cn/problem/P1396
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习