一学就废的并查集它来了

文章目录

  • 题目描述
  • 输入
  • 输出
  • 样例输入
  • 样例输出
  • 提示
  • 算法思想
  • 代码实现
    • 寻找根节点
    • 汇总连接情况
    • 完整代码
      • 关于flag的初值

题目描述

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?


输入

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。


输出

对每个测试用例,在1行里输出最少还需要建设的道路数目。


样例输入

4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0


样例输出

1
0
2
998


提示

Huge input scanf is recommended.


算法思想

数组下标作为一个点,数组中存储的元素作为其连接的另一个点,全联通即:将所有下标对应的点归拢到一个点上(也就是除了根节点,大家对应的都不是自己啦),相当于大家都跟一个点连接的话,当然是全联通状态啦。


代码实现


寻找根节点

定义一个函数用来搜索给出结点的根节点,最终返回根节点的值(康康大家是不是来自同一地方嘛)

int find(int x){while(data[x]!=x){x=data[x];}return x;//返回根节点的值
}

当联通关系不多,树的深度不深的时候,用上一种方法无疑是很快的,但是如果联通关系错综复杂,树的深度很深,例如每层只有一个节点这种奇葩情况,遍历搜索根节点就会很费时间,这时候就要用到“路径压缩“这一方法,即将所查询节点的数组内容由”父节点“改为”祖宗节点“。

int find(int x){//寻找根节点int ans,tmp;ans = x;while(data[x]!=x){//x是根节点x=data[x];}while (ans != x) {//路径压缩tmp = data[ans];data[ans] = x;//数组内容直接储存根节点,不再存储父节点ans = tmp;//接下来压缩父节点}return x;//返回根节点的值
}

汇总连接情况

将所给的两个点的连接情况进行记录,根节点不一样的话说明是第一次告知两个节点联通,所以要把根节点改成一样的, 一样的话当然就是告知过了,不需要改变(大型认祖归宗活动,哦兄弟我们是一家的,来来来族谱上记一下/哦兄弟我们是一家的,来来来……桥豆麻袋!族谱上记过了……不用记了诶)淦!你忘了我们很久以前见过面的!!!
⬆(淦!你忘了我们很久以前见过面的!!!)

void add(int x, int y){if(find(x)!=find(y)){data[find(x)]=find(y);}
}

完整代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;int data[1003];int find(int x){//寻找根节点while(data[x]!=x){x=data[x];}return x;//返回根节点的值
}void add(int x, int y){if(find(x)!=find(y)){data[find(x)]=find(y);}
}int main(int argc, char const *argv[]) {int n,m;//n元素个数,m元素连接条数int x,y;//x,y是两个相连的元素int flag;//未联通的结点数while (cin >> n,n) {memset(data,0,sizeof (data));for (int i = 1; i <= n; i++) {data[i] = i;}for (cin >> m; m > 0; m--) {cin >> x;cin >> y;add(x,y);}flag = -1;for (int i = 1; i <= n; i++) {if(data[i]==i){flag++;//数组内容等于数组下标表示和自己联通}}cout << flag << endl;}return 0;
}

关于flag的初值

其实难以理解的地方可能是flag的初值为什么要设置成-1,flag存储的是数组内容等于数组下标的情况(自己连接自己的情况)有多少,每有一个就说明有一种连接种类,全联通状态只有一个这样的情况——即根节点,也就是除了根节点和自己连接,其他的节点都不和自己连接,所以要把根节点这个情况排除在外,即flag初值为-1。
这样一来,当全联通时,只有根节点的data[i]=i,flag++,flag的值就为0,最后输出flag的值也就是还需要修多少条路。

举个栗子可能更方便理解
当输入为
5 2
1 2
4 5

此时data数组的情况是(第四行):在这里插入图片描述
连接种类有三种:根节点为2的1、2连接、根节点为3的自己和自己连接、以及根节点为5的4、5连接。
此时data[i]=i的情况会出现3次,flag的终值也就是-1自加三次,也就是2,表示还需要修两条路,举个例子,3 2,3 4这样修,那会出现什么情况呢?(为了便于理解拆分一下这个过程)
在这里插入图片描述
在这里插入图片描述
3 2的时候,3将2的根节点(也就是2本身)认作祖宗,3 4的时候,经过find函数查看族谱,诶大家祖宗不一样诶但我们是一家人,那就一个祖宗认另一个祖宗为爹好了,这样大家就在一起了,于是经过add函数修改族谱,3他爹2就认4他爹5当爹,1和3就成了5的乖孙孙。大家就是一家人了mua。(谁认谁当祖宗就看你怎么写了哦吼,data[find(x)]=find(y)是后面的数当前面的数的祖宗,data[find(y)]=find(x)就是前面的当祖宗咯)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443898.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一道很简单的贪心算法题~【贪心:我不要脸的伐?】

文章目录题目描述输入输出样例输入样例输出C语言代码实现思路排序处理完整代码C代码实现排序完整代码彩蛋题目描述 小健有一家自己的商店&#xff0c;主营牛奶饮品&#xff0c;最近资金紧张&#xff0c;他想以尽可能低的价格进购足够的牛奶以供日常的需要。所以小健想要求助你…

Eclipse 中修改java编译版本

修改方法是&#xff1a; 1&#xff1a;Preferences-->Java-->Compiler->Compiler compliance level&#xff0c;选择一个需要的版本&#xff0c;比如从默认的1.4改为5.0 2&#xff1a;如果只想修改一个工程的Compiler compliance level,就右单击工程&#xff0c;选择属…

百战c++(1)

Public和private的区别 public和private是类里的关键字&#xff0c;用于规定类内数据或者成员函数的访问权限。private类型的数据或者函数&#xff0c;只能在相应的类内被访问&#xff0c;而public类型的数据或者函数被访问的权限比较宽&#xff0c;还可以在其它类或者其它函数…

一学就废的三种简单排序【冒泡、插入、选择】

文章目录其他排序算法冒泡排序算法实现代码实例插入排序算法实现代码实例选择排序算法实现代码实例其他排序算法 一学就废的归并排序 冒泡排序 排列顺序从前到后或者从后往前都可&#xff0c;本文选择从后到前的顺序&#xff0c;升序排列&#xff1a;比较相邻两个元素&#x…

百战c++(2)

delete 和 delete []的真正区别 delete 对应 new delete[]对应new[]对于简单类型包括简单类型数组&#xff0c;delete 与delete[]没有区别。对于自定义类型数组&#xff0c;delete 只会删除一个元素&#xff0c;delete 则会删除所有元素。 指针和数组的区别 野指针是什么 野指…

shell预先定义的特殊变量

文章目录$#$*$$$# 表示命令行上参数的个数&#xff0c;但不包括shell脚本名本身 为脚本ex1赋予两个变量&#xff0c;测试$#的输出结果 [cmybogon test2]$ . ex1 ma.c mb.c 2 # echo $# 7 # cat $1 $2 $3 | wc -l 2 # echo $#脚本ex1的具体内容 [rootlocalhost test]$ cat ex1…

Linux实验一:常用的Linux命令

文章目录一、实验目的二、实验要求三、实验内容1、系统的使用2、命令的使用3、文件操作4、系统询问与权限口令5、其它常用命令四、实验操作1、基本命令的使用2、文件和目录操作3、创建用户帐户一、实验目的 1、熟悉Linux的桌面环境&#xff1b; 2、了解Linux所安装的软件包 3、…

Linux实验二:vi编辑器的使用

文章目录一、实验目的二、实验要求三、实验内容1、创建文件2、编辑文件一、实验目的 1、练习并掌握Linux提供的vi编辑器来编译C程序 2、学会利用gcc、gdb编译、调试C程序 3、本次实验的目的是让同学们了解如何使用vi编辑器进行创建和编辑文件 二、实验要求 1、文件编辑器vi…

百战c++(os1)

Linux中的锁 互斥锁&#xff1a;mutex&#xff0c;用于保证在任何时刻&#xff0c;都只能有一个线程访问该对象。当获取锁操作失败时&#xff0c;线程会进入睡眠&#xff0c;等待锁释放时被唤醒 读写锁&#xff1a;rwlock&#xff0c;分为读锁和写锁。处于读操作时&#xff0…

Linux实验三:Shell编程

文章目录一、实验目的二、实验要求三、实验内容1、通配符的使用2、重定向3、管道4、shell变量5、建立下面的脚本&#xff0c;运行并分析输出结果&#xff0c;并给出代码注释。6、编写脚本一、实验目的 1.为文件扩展名使用通配符 2.标准输入、标准输出和标准错误的重定向 3.使…

a href=#与 a href=javascript:void(0) 的区别

a href"#"> 点击链接后&#xff0c;页面会向上滚到页首&#xff0c;# 默认锚点为 #TOP<a href"javascript:void(0)" onClick"window.open()"> 点击链接后&#xff0c;页面不动&#xff0c;只打开链接<a href"#" οnclick&…

Linux实验四:编译和调试工具的使用

文章目录一、实验目的&#xff1a;二、实验要求三、实验内容四、实验操作1、用gcc编译程序&#xff0c;写出编译过程&#xff0c;并给出运行结果。2、调试程序&#xff0c;要求用gdb进行调试并给出修改方案。3、make的使用一、实验目的&#xff1a; 1、练习并掌握Linux提供的v…

Linux实验五:Linux环境下的C语言编程

文章目录一、实验目的&#xff1a;二、实验要求三、实验内容1、编写一段C语言程序使其完成&#xff1a;父进程创建两个子进程&#xff0c;每个进程都在屏幕上显示自己的进程ID号。2、上机调试下面的程序&#xff0c;观察运行结果&#xff0c;分析原因。3、利用两个管道进行双向…

百战c++(4)

1.求下面函数的返回值&#xff08;微软&#xff09; int func(x) { int countx 0; while(x) { countx ; x x&(x-1); } return countx; } 假定x 9999。 答案&#xff1a;8 思路&#xff1a;将x转化为2进制&#xff0c;看含有的1的个数。 2. 什么是“引用”&…

ndarray对象的建立

文章目录ndarray&#xff08;别名array&#xff09;常用属性创建NumPy数组使用array()函数使用zeros()函数使用ones()函数使用empty()函数使用arange()函数注意ndarray&#xff08;别名array&#xff09; 常用属性 import numpy as np # Numpy工具包data np.arange(12).res…

百战c++(5)

11. 已知strcpy的函数原型&#xff1a;char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串&#xff0c;strSrc 是源字符串。不调用C/C 的字符串库函数&#xff0c;请编写函数 strcpy。 答案&#xff1a; char *strcpy(char *strDest, const char *strS…

Numpy数组的广播机制

文章目录前言数组广播广播机制的使用条件前言 Numpy数组不需要循环遍历&#xff0c;即可对每个元素执行批量的算术运算操作&#xff08;矢量化运算&#xff09;。当两个数组大小&#xff08;Numpy.shape&#xff09;不同时&#xff0c;进行算术运算会出现广播机制。 数组广播…

百战c++(6)

26. 描述内存分配方式以及它们的区别? 1&#xff09; 从静态存储区域分配。内存在程序编译的时候就已经分配好&#xff0c;这块内存在程序的整个运行期间都存在。例如全局变量&#xff0c;static 变量。 2&#xff09; 在栈上创建。在执行函数时&#xff0c;函数内局部变量的…

Spring3.1.0+Quartz1.8.6整合实现计划任务

1.首先要加入任务计划的相关的jar包&#xff0c;这里除了需要加Spring3.1.0的jar&#xff0c;还需要加quartz-all-1.8.6.jarslf4j-api-1.5.8.jar slf4j-log4j12.jar这三个包&#xff0c;如果你是SSH整合的项目&#xff0c;里面有下面的两个包了&#xff0c;就可以不加&#xff…

百战c++(7)

40. 链表题&#xff1a;一个链表的结点结构 struct Node { int data ; Node *next ; }; typedef struct Node Node ; (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel) Node * ReverseList(Node *head) //链表逆序 { if ( head NULL || head->next NU…