并查集——以vijos《家族》为例

并查集可以用来查询两个点是否在同一个集合中,相比于用图dfs,效率大大提升,这里放两个截图对比一下

并查集——以vijos《家族》为例_第1张图片并查集——以vijos《家族》为例_第2张图片


怎么样,时间差距很大吧!

其实并查集的思想就是找出要合并的点的最大公共祖先,这样我们在判断两个点是不是在同一个集合里只要判断他们的祖先是不是相同就行了。

这里先讲并查集的几个操作:

1:初始化:

void init (){
	for (int i=1;i<=n;i++) f[i]=i;
}

2:找祖先:

int getf(int v){
	if (f[v]==v){//如果f[v]==v那么就找到当前的祖先了 
		return v;
	}
	else{
		f[v]=getf(f[v]);//如果不是就往上一层节点跳 
		return f[v];//继承祖先 
	}
}

3:合并:

void merge(int v,int u){
	int t1,t2;
	t1=getf(v);
	t2=getf(u);
	if (t1!=t2){
		f[t2]=t1;//这里让左边的祖先成为为右边的祖先
	}
}

完整代码如下:

#include 
#include 
#include 

using namespace std;

//定义变量
int n,m,q,f[5005]; 

void init (){
	for (int i=1;i<=n;i++) f[i]=i;
}

int getf(int v){
	if (f[v]==v){//如果f[v]==v那么就找到当前的祖先了 
		return v;
	}
	else{
		f[v]=getf(f[v]);//如果不是就往上一层节点跳 
		return f[v];//继承祖先 
	}
}

void merge(int v,int u){
	int t1,t2;
	t1=getf(v);
	t2=getf(u);
	if (t1!=t2){
		f[t2]=t1;
	}
}

int main(){
	
	cin>>n>>m>>q;
	int temp_x,temp_y;
	init();//初始化 
	for (int i=1;i<=m;i++){
		cin>>temp_x>>temp_y;
		merge(temp_x,temp_y);
	}
	
	for (int i=1;i<=q;i++){
		cin>>temp_x>>temp_y;
		if (f[getf(temp_x)]==f[getf(temp_y)]){//这里要在找一次father,因为我们在之前合并时可能会没有把某个点的儿子的祖先修改为该节点最远祖先
			cout<<"Yes"<

你可能感兴趣的:(算法)