【图论_并查集】

一种特殊的数据结构——并查集

并查集的思想主要用来找一些数据之间的关系

或许你并不知道,你的某个朋友是你的亲戚,他可能是你曾祖父的外公的女婿的外甥女的表姐的孙子。所以为了解决你周围的人和你是不是有亲戚关系,我们就需要并查集的思想qwq。

思想:合并集合的思想,可以理解为找共同的祖先,在数学上或许可以看成把同源的人合并到一个集合里:

(找不到图感性理解吧)

总之概括一下就是一个合并查找的过程。(通俗一点:“找祖宗”)

下面来看一个eg:

【洛谷p1551】亲戚

算法就一个“并查集”(孤零零),是很典型的例题了。

思路:

初始状态,每个人的父亲都是他自己qwq

for(int i=1;i<=n;i++)
      father[i]=i;

开始输入两个人的亲戚关系:

1.寻找他们的祖先并合并

如果他们不是同一个祖先,因为他们有亲戚关系,故把他们合并成一个集合

int find_father(int x){//寻找祖先,递归操作
if(father[x]!=x) return find_father(father[x]);
return x;
}

/*int find_father(int x){//进行优化,使每个人的“father”直接指向”老祖宗“,避免重复递归的时间
    if(father[x]!=x)father[x]=find_father(father[x]);
    return father[x];
}*/

void unionn(int x,int y){//合并两个集合(因为通过不断”找father“,一定可以判断他们是一个集合中的,这里规定谁是谁的father看习惯)
    father[y]=x;
}





for(int i=1;i<=m;i++){
        cin>>mi>>mj;//输入某两个人的亲戚关系
        int r1=find_father(mi);//找mi的祖先
        int r2=find_father(mj);//找mj的祖先
        if(r1!=r2)unionn(r1,r2);//如果他们祖先不同,那么就合并(避免重复合并
    }

查:查找两个人是否有亲戚关系:

for(int i=1;i<=p;i++){
        cin>>pi>>pj;
        if(find_father(pi)==find_father(pj))
            cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }

我们把代码也并查集一下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,p,mi,mj,pi,pj;
int father[5001];
void unionn(int x,int y){
    father[y]=x;
}
int find_father(int x){
    if(father[x]!=x)father[x]=find_father(father[x]);
    return father[x];
}
int main(){
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=n;i++)
      father[i]=i;
    for(int i=1;i<=m;i++){
        cin>>mi>>mj;
        int r1=find_father(mi);
        int r2=find_father(mj);
        if(r1!=r2)unionn(r1,r2);
    }
    for(int i=1;i<=p;i++){
        cin>>pi>>pj;
        if(find_father(pi)==find_father(pj))
            cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}

end-

posted @ 2019-04-23 19:06  Sweetness  阅读(280)  评论(0编辑  收藏  举报