洛谷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-树的大小(其实就是多开一个结构体,基本方法还是并查集)计算还应当修建的路径条数。
posted @   lazy_ZJY  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示