所谓并查集,就是将一些有关系的东西合并起来,用于方便查找。
在此我也不讲太多理论的东西(理论参看高级数据结构.pdf中并查集部分),还是讲讲实际应用吧。
顾名思义,并查集就是并着查的集合。对他的操作有两种:
查找操作:(查找某个元素所在的集合):
查找操作
要表示一个集合,就要加上一个标记,那些用什么来标记呢,就用他的第一个元素。
在此我也不讲太多理论的东西(理论参看高级数据结构.pdf中并查集部分),还是讲讲实际应用吧。
顾名思义,并查集就是并着查的集合。对他的操作有两种:
查找操作:(查找某个元素所在的集合):
查找操作
要表示一个集合,就要加上一个标记,那些用什么来标记呢,就用他的第一个元素。
合并操作:(将两个集合合并):
将所要和并的两个元素所在集合的标记节点合并。
接下来我们来看几道例题:
家 族
描述 Description
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
输入格式 Input Format
第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Ai和Bi具有亲戚关系。接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。
输出格式 Output Format
P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。
该题是标准并查集经典题目,只要找标记就行了。
程序如下:
读入数据,将节点的标记记为他自己:
#include<iostream>
using namespace std;
int a[5000];
int i,j,k,m,n,p;
void Init()
{
for(int i=1;i<=n;i++)
a[i]=i;
}
int fun(int x)
{
if(a[x]!=x)
{
a[x]=fun(a[x]);
return a[x];
}
else return x;
}
int main()
{
cin>>n>>m>>p;
Init();
for(int i=1;i<=m;i++)
{
cin>>j>>k;
if(fun(j)!=fun(k)) a[fun(k)]=j;
}
for(int i=1;i<=p;i++)
{
cin>>j>>k;
if(fun(j)==fun(k)) cout<<"YES\n";
else cout<<"NO\n";
}
}