Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 735|回复: 0

[默认分类] 【算法笔记】并查集

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-3-15 14:51:08 | 显示全部楼层 |阅读模式

    并查集这玩意上课老师没讲,听上去就很高大上,一看到题目说要用并查集,ψ(。。)什么!?并查集?什么玩意?算了算了,放弃这道题刷别的吧。今天研究了下并查集,发现还是挺简单的,博客上做个整理,以后忘了上来瞅瞅_(¦3」∠)_

    并查集

    并查集主要是用来检测两个点是否连通的,主要有两个功能,一个是find一个是join。至于什么时候用并查集,我想大概是你觉得需要判断这两个点是否连通吧,例如,几个个城市之间有几条几条路,判断其中两个城市是否连通。

    ①并查集的初始化

        并查集一般是用一个一维数组来存储的,其中pre=i表示自己和自己是连通的,也就是说还没有往点之间添加路径。


    ②并查集join

        join主要是用来往存放并查集的一维数组中添加路径的,先判断两个点之间是否连通,如果连通就不用添加路径了,如果不连通那么将两个点的根节点连在一起。

    void join(int x,int y){
            int i,j;
            i = find(x);  //寻找x的根节点
            j = find(y);  //寻找y的根节点
            if(i!=j)  //如果两个根节点不同,即不连通,将根节点连在一起
                    pre = j;  //即i链接j
    }③并查集find

        find主要有两个部分,一个是寻找根节点,一个是将路径压缩。

    int find(int x){        int i = x;        while(pre!=i)  //查找根节点                 i = pre;        //路径压缩        int j = x;        int k;        while(j!=i)           {                k = pre[j];                pre[j] = i;                j = k;        }        return i;}下面有两道例题来详细讲解一下并查集的用法

    蓝桥杯 历届试题 风险度量

    X星系的的防卫体系包含 n 个空间站。这 n 个空间站间有 m 条通信链路,构成通信网。
    两个空间站间可能直接通信,也可能通过其它空间站中转。
    对于两个站点x和y (x != y), 如果能找到一个站点z,使得:
    当z被破坏后,x和y无法通信,则称z为关于x,y的关键站点。
    显然,对于给定的两个站点,关于它们的关键点的个数越多,通信风险越大。
    你的任务是:已知网络结构,求两站点之间的通信风险度,即:它们之间的关键点的个数。

    输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,链路数。
    空间站的编号从1到n。通信链路用其两端的站点编号表示。
    接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条链路。
    最后1行,两个数u,v,代表被询问通信风险度的两个站点。

    输出:一个整数,如果询问的两点不连通则输出-1.

    例如:
    用户输入:
    7 6
    1 3
    2 3
    3 4
    3 5
    4 5
    5 6
    1 6
    则程序应该输出:
    2

    #include<iostream>using namespace std;int pre[1001];int u[2001],v[2001];int find(int x){        int i = x;        while(pre!=i)  //查找根节点                 i = pre;        //路径压缩        int j = x;        int k;        while(j!=i)           {                k = pre[j];                pre[j] = i;                j = k;        }        return i;}void join(int x,int y){        int i,j;        i = find(x);        j = find(y);        if(i!=j)                pre = j;}int main(){        int n,m;        cin>>n>>m;        int i,x,y;        for(i=0;i<n;i++)                 pre = i;        for(i=0;i<m;i++)        {                cin>>x>>y;                u = x;                v = y;                join(x,y);        }        cin>>x>>y;        if(find(x)!=find(y))  //如果不连通就输出-1                cout<<"-1"<<endl;        else  //如果连通,寻找有几个关键站点        {                int res = 0;                for(i=0;i<n;i++)  //因为数据很小,所以暴力枚举,从第一个站点开始判断是否是关键站点                  {                        if(i==x||i==y)   //如果i是x和y这两个需要判断是否连通的站点的其中一个就跳过                                 continue;                        for(int k=0;k<n;k++)  //初始化pre数组                                 pre[k] = k;                        for(int j=0;j<m;j++)  //按照输入顺序jion                        {                                if(u[j]==i||v[j]==i)  //如果是i这个站点,就不在pre里面加链接这个站点的路径                                        continue;                                join(u[j],v[j]);                        }                        if(find(x)!=find(y))  //如果x和y不连通了,说明站点i是关键站点                                 res++;                }                cout<<res<<endl;        }        return 0;}2005年浙江大学计算机复试 通畅工程  NYOJ608
    畅通工程时间限制:2000 ms  |  内存限制:65535 KB
    难度:3
    描述某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路? 输入测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
    注意:两个城市之间可以有多条道路相通,也就是说
    3 3
    1 2
    1 2
    2 1
    这种输入也是合法的
    当N为0时,输入结束,该用例不被处理。输出对每个测试用例,在1行里输出最少还需要建设的道路数目。样例输入4 21 34 33 31 21 32 35 21 23 5999 00样例输出102998输出对每个测试用例,在1行里输出最少还需要建设的道路数目。样例输入4 21 34 33 31 21 32 35 21 23 5999 00样例输出102998#include<iostream>#include<stdio.h>using namespace std;int pre[1005];int find(int x){        int i = x;        while(pre!=i)                 i = pre;        return i;}int main(){        int n,m;        int i,a,b,total,fa,fb;        while(scanf("%d",&n) && n!=0)        {                scanf("%d",&m);                total = n-1;  //n个站点全部连通最少需要n-1条路径                for(i=1;i<=n;i++)                        pre = i;                for(i=1;i<=m;i++)                {                        scanf("%d%d",&a,&b);                        fa = find(a);                        fb = find(b);                        if(fa!=fb)                                pre[fa] = fb;                }                for(i=1;i<=n;i++)                {                        if(pre!=i)  //也就是有相连的路径                                total --;                }                printf("%d\n",total);        }        return 0;}
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-17 06:59 , Processed in 0.408742 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表