畅通工程
思路
城市之间由道路连接,相连的城市可以看做一个集合,如:a、b相连,c、d相连,则a和b属于集合A,c和d属于集合B。之后又有人告诉你b和e相连,那么就把e加入到集合A中,以此类推。然后不同集合若是想组成一个大的集合,即集合A和集合B若相连接在一起,那随便在两个集合中分别找两个城市连接在一起就可以了。
考点
并查集
#include<stdio.h>
int fa[1010];
int find(int i){//寻找 根(父节点)
if(fa[i]!=i){//领导人的集合就是自己
fa[i]=find(fa[i]);//递归实现找到最终的领导人
}
return fa[i];
}
void merge(int x,int y){//合并,使其各根(父节点)归属为一个最终根上
int tx,ty;
tx=find(x);
ty=find(y);
if(tx!=ty){
fa[ty]=tx;//将两领导人归属到其中一个最终大boos上
}
}
int main()
{
int n,m,x,y;
while(scanf("%d",&n)==1){
if(n==0) break;
for(int i=1;i<=n;++i){//注意:开始必须初始化所有的节点的前导都是自己,
fa[i]=i;
}
scanf("%d",&m);
for(int j=0;j<m;++j){
scanf("%d%d",&x,&y);
merge(x,y);
}
fa[0]=-1;//两个城镇一条路
for(int i=1;i<=n;i++){
if(fa[i]==i)//大boos就是本身,所以找有多少本身,就有几个大booss(不相干集合)
fa[0]++;
}
printf("%d\n", fa[0]);
}
return 0;
}
老师视角
*分析
1.连通的城镇在一个集合中,不连通的城镇分布在互不相交的集合中,集合是树形结构
2.初始时,各个城镇互不连通,即有N个集合(N个互不相交的集合)
3.在查询过程中,查询路径上的城镇成为根的儿子,称为:路径压缩。
#include<bits/stdc++.h>
using namespace std;
#define MXN 1010
int N, M, fa[MXN];
int find(int r){
if(r != fa[r]) fa[r] = find(fa[r]); // 路径压缩
return fa[r];
}
void merge(int a, int b){
int t1 = find(a);
int t2 = find(b);
if(t1 != t2) fa[t1] = t2;
}
int main(){
int x, y;
while(scanf("%d", &N) == 1){
if(N == 0) break;
scanf("%d", &M);
for(int i = 1; i <= N; i++) fa[i] = i;
for(int i = 1; i <= M; i++){
scanf("%d %d", &x, &y);
merge(x, y);
}
fa[0] = -1;
for(int i = 1; i <= N; i++) if(fa[i] == i) fa[0]++;
printf("%d\n", fa[0]);
}
return 0;
}