好吧,什么垃圾并查集,并查集什么的都是铁憨憨<+__+>php
如今开始复习回忆:(新手,有错误望指正)数组
什么叫作并查集,并查集就是一个集合问题,其实最主要的就是知道并查集是一个求解集合数目的问题,具体的操做方法有点飘。函数
或者这样理解:——并查集经过一个一维数组来实现,其本质是维护一个森林。(好吧,我也不是很理解),个人理解就是经过一维数组来实现,子节点与父节点之间联系,而后查找集合个数。。。。。。。优化
好吧,不清楚,若是看了前面你很懵逼,那就全都忘了吧,,,spa
接下来才是正餐:https://blog.51cto.com/ahalei/2348145code
直接上代码:blog
题目是杭电的畅通工程:http://acm.hdu.edu.cn/showproblem.php?pid=1232递归
#include<stdio.h> int fa[1001]={0}; void zore(int n)//未知量用n表示,初始化 { for(int i=1;i<=n;i++) fa[i]=i; } int find_father(int x)//返回老大,或者说是根节点 { if(fa[x]== x) return x; else{ fa[x]=find_father(fa[x]);//优化路径 return fa[x]; } } void unions(int n,int m) { if(find_father(n)!=find_father(m)) fa[find_father(m)]=find_father(n); } int main() { int n,m; while(scanf("%d %d",&n,&m)&&n) { int sum=0; zore(n); while(m--) { int a,b; scanf("%d %d",&a,&b); unions(a,b); } for(int i=1;i<=n;i++) { if(fa[i]==i) sum++; } printf("%d\n",sum-1); } return 0; }
如今咱们把代码拆开来讲:io
int main() { int n,m;//题目中的n表明城市个数,m表明道路数 while(scanf("%d %d",&n,&m)&&n) { int sum=0;//用来预装须要修的路数 zore(n);//调用初始化函数,来使咱们的一维数组初始化 while(m--)//输入m条路 { int a,b;//a,b分别表明道路的起始城市的标号 scanf("%d %d",&a,&b); unions(a,b);//合并有相邻道路的城市,为最后计算道路数作准备:好比最后若是只有两个集合,只须要修一条路;三个集合两条路的思想。 } for(int i=1;i<=n;i++) { if(fa[i]==i)//寻找到底有几个独立集合
sum++; } printf("%d\n",sum-1); } return 0; }
接下来:class
int fa[1001]={0}; void zore(int n)//初始化做用,这点很重要,由于这个操做为咱们接下来的操做提供了数据 { for(int i=1;i<=n;i++) fa[i]=i; }
再接下来:
int find_father(int x)//这个very very重要 { //做用是查找根结点,父节点...>若是你看过第一篇文章,你就把他理解成最大的BOOS就行了 if(fa[x]== x)若是查找点本身就是本身的最大BOOS,则返回 return x; else{ fa[x]=find_father(fa[x]);//优化路径,其实 是一个递归调用 return fa[x];//优化事后改变了树的结构, 子节点不少直接变成了根结点 } }
再接下来再:
void unions(int n,int m) { if(find_father(n)!=find_father(m))//合并操做..>其实就是当两我的的老大不一我的的时候,然而却须要创建联系,好吧,这个时候两我的就要开始干架了,最直接的方法是
fa[find_father(m)]=find_father(n);//直接让两我的的老大来谈话,让一个老大认另外一我的的老大为老大,此时他们就属于同一个集合,此时就消除了集合间的隔离,或者说
//合并了两个集合 }
void unions(int x,int y) { int b1=find_father(n);//或者变成这样,x市到y市之间有一条路,查询x与y市的老大是谁 int b2=find_father(m); if(b1!=b2)//判断x与y市在不在一个集合 fa[b1]=b2;//若是不在,合并 }