洛谷P1536 村村通
传送门:P1536 村村通
人间风起,四季同书。(还是一篇 817 的做题记录la~)
题意:
有好多组数据,每组数据给你 m 条无向边的信息(u,v);
问你最少再添加多少条边就能使整张图连通。
思路:
首先我们要知道,一个图如果连通,边的数量最少是 n-1;
但是题目会出现这样一种情况:
n = 4,m = 3; 1 <——> 2 , 2 <——> 3 , 3 <——> 1;
这时候整张图变成了一个环和一个孤点,整张图并不联通
我们再观察会发现:
1 与 3 相连之前,1 与 3 就已经属于一个连通块了
换句话说就是 最后一条边加与不加是等效的
特殊 --> 一般:
如果两个点在添加这一条边之前已经属于同一连通块,就可以看作没有这条边
很自然地想到 并查集 就是求 kruscal 的东东
就是在读入两个点时,用 ans 记录此时加入图中对连通性真正有用的边的数量
- 如果 他们不属于同一个连通块,那么这条边有用,将两个点所在的连通块合并,ans+1;
- 如果 他们已经属于同一个连通块,那么这条边没用,不做任何处理
就转换成:
并查集 合并两个连通块、查询祖先
还是很好实现的啦 !
最终代码:
- 注意这个
非常神经有意思的输入 - 并查集查寻祖先时,路径压缩(我的爸爸的祖先就是我的祖先)
- 最终答案是 n-1(图中应当有的有用边的数量)与 ans(现在图中有用边的数量)的差
#include<bits/stdc++.h> using namespace std; const int maxn=1010; int m,n; int to[maxn]; int ans; int go(int p) { if(p==to[p])return to[p]; else return to[p]=go(to[p]);//路径压缩 } int main() { while(1) { ans=0; cin>>n; if(n==0)return 0;//注意一下这个奇葩的读入 cin>>m; for(int i=1;i<=n;i++) { to[i]=i; } for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; if(go(x)!=go(y))//还不属于一个并查集 { //合并 ans++; to[go(x)]=to[go(y)]; } } cout<<n-1-ans<<endl; } return 0; }
后记:
- 这道题目主要考察了 并查集 的有关知识
非常板子。 - 当然也能用 kruscal 将每个边的边权置为 1 ,求一边最小生成树,再用 n-1-树的大小(其实就是多开一个结构体,基本方法还是并查集)计算还应当修建的路径条数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!