[题解]P1536 村村通

P1536 村村通

这是一道比较模板的生成树和并查集题,想了一会然后敲出来了,但是因为下标没有从1开始调了半天……

(啊,我这人就爱犯这种错误)

那么,思路是什么呢?

我们发现,每连成1个环,就要多浪费1条边,因为这1条路本来可以往外再连接1个村庄的。

所以,我们需要跑一遍最小生成树,计下cnt,也就是形成环的边的总数。

用m(边的个数)去减cnt,得到的结果就是不形成环的边的总数,存入一个临时变量t中。

这些边经过点的个数就是边的个数+1,即t+1。

最后,用点的总数去减,得到剩下的没有连接的点的个数,输出即可。

附上代码:

 1 #include<iostream>
 2 using namespace std;
 3 struct edge{
 4     int u,v;
 5 }edges[500010];//完全图中m=n(n-1)/2
 6 int n,m,fa[1010];
 7 int find(int x){//并查集之 查
 8     if(fa[x]==x) return x;
 9     return fa[x]=find(fa[x]);
10 }
11 int main(){
12     while(cin>>n){
13         if(n==0) break;
14         cin>>m;
15         for(int i=1;i<=n;i++) fa[i]=i;
16         for(int i=1;i<=m;i++){
17             cin>>edges[i].u>>edges[i].v;
18         }
19         int cnt=0;
20         for(int i=1;i<=m;i++){
21             int x=find(edges[i].u),y=find(edges[i].v);
22             if(x==y){//形成环
23                 cnt++;
24                 continue;
25             }
26             fa[x]=y;//并查集之 并
27         }
28         int t=m-cnt;
29         cout<<n-t-1<<endl;
30     }
31     return 0;
32 }
View Code

其实这一份代码还是有一些缺陷的,比如说完全不需要用结构体数组来存,现读现算即可。可是懒得改啦

 

个人感觉生成树一类的题目都不用单独去写一个union(合并)函数,直接在主函数中一个语句完事。毕竟生成树都是在两点祖先不同的时候进行合并,既不用再求一次祖先,也不需要单独判断要不要合并。

洛谷的题解中,大部分的思路和这个不太一样。主要是:跑完最小生成树记录多少点的祖先是它本身(祖先是本身就说明这是一个连通块),输出时减去1;也有用桶来存祖先节点,然后遍历输出为1的个数……但除了初始化,这些算法都免不了一两个n次的循环,但我这个算法不需要(嘿嘿)

第一次写题解,感觉很多地方写得不是很清晰,如果有任何想说的请发在评论区,我会认真阅读的。谢谢!

posted @ 2023-11-13 16:48  Sinktank  阅读(57)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.