电子学会六级-数据结构-并查集

并查集
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

海滩防御
https://www.luogu.com.cn/problem/P1783

posted @ 2022-04-28 16:31  new-code  阅读(16)  评论(0编辑  收藏  举报