求解连通性问题,最好用的当然是并查集了,可以使用深搜或者广搜。
这道题目的意思是给定一些道路,如果把其中一个顶点去掉,那么需要建立多少条道路才能联通所有顶点。
这道题目如果用朴素的并查集的话第四个测试用例会超时,因此想到带路径压缩的并查集。递归或者非递归方式都可以,对于这道题目来说不会差别很大,不过用递归可能会有栈溢出的问题,当数据量小的时候没有什么大问题。(其实递归的深度不会很大,所以RE得风险应该很小的,已建立起来的数目只有两层。错误,比如两个帮派老大带了一群小弟,一个帮派老大投靠了另外一个小弟,那么就会出现三层的情况,并不是说并查集就是一定是两层的,可能会有多个两层合在一起,那么就出现三层了)
#include<stdio.h> #include<stdlib.h> #define MAX 1010 struct Edge { int a; int b; }edge[MAX*MAX]; int father[MAX]; void init(int n) { for(int i=1;i<=n;i++) father[i]=i; } void output(int n) { for(int i=1;i<=n;i++) printf("%d ",father[i]); } int findFather(int x) { while(x!=father[x]) x=father[x]; return x; } int findFatherWithCompress(int x)//4 答案正确 119 4216 4/4 递归寻找父亲节点,然后把节点挂载到父亲节点上 { if(x!=father[x]) father[x]=findFatherWithCompress(father[x]); return father[x]; } int findFatherWithCompress2(int x)//开始先找到x的父亲节点,此时并未压缩,然后沿着x-->father[x]一直压缩路径,把节点直接赋值给最顶层的父亲节点 { int r=x; while(r!=father[r]) r=father[r]; int k=x; while(father[k]!=r) { int j=father[k];//j exchange for father[k] father[k]=r; k=j; } return r; } void merge(int a,int b) { int x=findFatherWithCompress2(a); int y=findFatherWithCompress2(b); if(x!=y) father[x]=y; //find father and merger them } int main() { int n,m,k; freopen("1013-in.txt","r",stdin); freopen("1013-out.txt","w",stdout); while(scanf("%d%d%d",&n,&m,&k)!=EOF) { for(int i=0;i<m;i++) scanf("%d%d",&edge[i].a,&edge[i].b); for(int j=0;j<k;j++) { init(n); int c,a,b; scanf("%d",&c); for(int i=0;i<m;i++) { a=edge[i].a; b=edge[i].b; if(a==c||b==c) continue; merge(a,b); } int count=0; //output(n); for(int i=1;i<=n;i++) { if(father[i]==i) { count++; } } printf("%d\n",count-2);//except the city } } return 0; }
时间: 2024-12-27 21:09:53