关于这道题我先来贴两个链接:
https://www.cnblogs.com/stdcpsx/p/13188989.html 我就是看李老师的这篇博客A掉了这道题,代码写的真的超级好,一环扣一环
https://blog.csdn.net/qq_41593380/article/details/81146850 一开始看李老师亲戚这道题的代码看不太懂,后来发现了这篇博客,把并查集描写的很形象
这次不把我的解题过程写出来了(毕竟也没有解题过程qwq,就是看了李老师的博客会了然后A了
首先是把整个代码放一下:
#include<iostream> #include<cstdio> using namespace std; int n,m,a,b,hh[10010]; int find(int ans){ if(hh[ans]==ans) return ans; hh[ans]=find(hh[ans]); return hh[ans]; } int main(){ while(true){ int sum=0; scanf("%d",&n); if(n==0) break; scanf("%d",&m); for(int i=1;i<=n;i++){ hh[i]=i; } for(int i=0;i<m;i++){ scanf("%d%d",&a,&b); hh[find(a)]=find(b); } for(int i=1;i<=n;i++){ if(hh[i]==i){ sum++; } } if(sum==0) printf("%d ",sum); else printf("%d ",sum-1); } return 0; }
然后一会在解释代码的时候你如果发现你有很迷惑的地方就来看看整体代码就会解决的
递归部分(很重要的!!
int find(int ans){//用来查找自己树根的递归函数 if(hh[ans]==ans) return ans;//如果这个参数他是树根或者这个参数他没有任何道路可以通行,就直接返回ans。为什么hh[ans]=ans表示没有任何道路可以通行呢?你可以选择继续看下去,我认为这里李老师写的很妙 hh[ans]=find(hh[ans]);//如果他不符合上面判断中的条件,那么就递归去找他的树根 return hh[ans];//最后求出来的结果return就好了 }
上面这个for循环很绝,重要程度不亚于递归部分,但是它的主要作用要在讲下面代码时会一起说,直接说这个for的作用可能有点难理解
for(int i=1;i<=n;i++){ hh[i]=i; }
下面的第一个for是输入+认树根
hh[find(a)]=find(b); 这一句话的意思就是让b的根,变成a的根的父亲,这样一来a和b就是一家人了,他们都有一个共同的树根,隶属于同一个祖宗下。
第二个for是计算还需要铺设的道路条数,判断语句中的hh[i]==i,意思就是判断一下有没有链接这个城镇的道路(因为在上面的for中已经把亲戚树建好了,所以直接判断就好了)
for(int i=0;i<m;i++){ scanf("%d%d",&a,&b); hh[find(a)]=find(b); } for(int i=1;i<=n;i++){ if(hh[i]==i){ sum++; } }
然后最后我们把代码运行测试样例会发现:输出的结果除了输出0剩下的都会比正确答案+1。这不简单吗?直接特判就好了:
if(sum==0) printf("%d ",sum);//如果是0就直接输出 else printf("%d ",sum-1);//如果不是0就-1输出
最后你就可以A掉它了
然后你们一定要去看看我上面贴的两个链接!!(大声bb