每日学习-2月2日

知识点:并查集

并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题。

一些常见的用途有求连通子图,求最小生成树的Kruskal算法和求最近公共祖先(LCA)等。

并查集的基本操作主要有:

1.初始化int    2.查询find    3.合并unionn

1.初始化:

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

假如有编号为1,2,3,......n的n个元素,我们用一个数组fa[ ]来存储每个元素的父节点。一开始,我们先将它们的父节点设为自己。

每日学习-2月2日_第1张图片

2.查询

找到 i的祖先先直接返回(未进行路径压缩)

int find(int i)
{
   if(fa[i]==i)//递归出口,当到了祖先位置,就返回祖先
    return i;
   else
    return find(fa[i]);//不断往上查找祖先
}

优化:路径压缩 

每日学习-2月2日_第2张图片

3.合并

void unionn(int i,int j)
{
   int i_fa=find(i);
   int j_fa=find(j);
   fa[i_find]=j_fa;
}

例题:

现在有若干家族图谱关系,给出了一些亲戚关系,如Marry和Tom是亲戚,Tom和Ben是亲戚等等。从这些信息中,你可以推导出Marry和Ben是亲戚。请写一个程序,对于我们的关于亲戚关系的提问,以最快速度给出答案。

输入格式:

第一部分是以N,M开始。N为人数(1<=N<=2000),这些人的编号为1,2,3,......,N。下面有M行(1<=M<=1000000),每行有两个数a,b,表示a和b是亲戚。

第二部分是以Q开始。以下Q行有Q个询问(1<=Q<=1000000),每行为c,d,表示询问c和d是否为亲戚。

输出格式:

对于询问c,d输出一行:若c,d为亲戚,则输出“YES”,否则输出“NO”

每日学习-2月2日_第3张图片

代码如下:

#include
#define MAXN 20001
int fa[MAXN];
void init(int n)
{
	for(int i=1;i<=n;i++)
		fa[i]=i;
}
int find(int x)
{
	if(x==fa[x])
	return x;
	else
	{
		fa[x]=find(fa[x]);
		return fa[x];		
	}
}
void unionn(int i,int j)
{
	int i_fa=find(i);
	int j_fa=find(j);
	fa[i_fa]=j_fa;
}
int main()
{
	int n,m,x,y,q;
	scanf("%d",&n);
	init(n);
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		unionn(x,y);
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		if(find(x)==find(y))
		{
			printf("YES\n");
		}                
		else 
	    printf("NO\n");
	}
	return 0;
 } 

 

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