一、题目:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6ab12c86c8ed45088488c31f9ec05d6a.png)
二、题解:
1、看到求联通块问题,我们可以考虑使用DFS/并查集(在这里我们仅介绍并查集)
2、什么是并查集?
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/07f14c3dbf354a5aa977d15350c9a003.png)
2.1:初始化:对于每一个点,我们都对其进行初始化操作pre[i]=i
pre[i]
表示i
的根节点
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/75c8571b1e4d43dc8e057c80b456ffd1.png)
2.2:root()
函数:求解一个节点的根节点(末节点)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0bad35f99ade44509759123d43886c57.png)
- 代码如下:
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b88bd4027f244283abb1e40f3bd7582d.png)
int root(int u)
{if(pre[u]==u) return u;else {pre[u]=root(pre[u]); return pre[u];}
}
2.3:合并(连接)函数merge()
u
的根节点与v
的根节点相连接
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b18572ce59fb46afaa03301aa90d22a1.png)
void merge(int u,int v)
{pre[root(u)]=root(v);
}
2.4:查找(查询)函数:Iscon(u,v)
检验u
,v
的根节点是否相同
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4662b9d2e8ec4903b8285a0f77714f43.png)
2.5:路径压缩
- 1):在朴素的想法中,我们如果要查询一个点的
root
节点,需要递归 n n n次root(u)
,但是中间的一整段其实都是无用的,因此我们可以使用路径压缩
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55959d4bd24844f38445e0fd6e3dbf9f.png)
- 2):所谓路径压缩,类似记忆化搜索,就是在递归时把所有求过了的
pre[i]
都保存一下 PS:因为同一联通块上的root
都相等 - 总结来说,就是对于并查集,所有的操作都在根上
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e9fc81cc07964481ad6190bea35de2c4.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/633ed9c6bb354f27814e4a5727be27a6.png)
int root(int u)
{if(pre[u]==u) return u;else {pre[u]=root(pre[u]); return pre[u];}
}
2.6:统计个数(桶的思想)
- 对于每一个节点,可以存储它的根节点
- 随后遍历、排序、输出即可
for(int i=1;i<=n;i++) cnt[root(i)]++;vector<int>v;
for(int i=1;i<=n;i++)
{if(cnt[i]!=0) v.push_back(cnt[i]);
}sort(v.begin(),v.end());
for(auto &i:v) cout<<i<<' ';
3、完整代码如下:
#include<bits/stdc++.h>
using namespace std;const int N=2e5+7;
int pre[N];
int cnt[N];int root(int u)
{if(pre[u]==u) return u;else {pre[u]=root(pre[u]); return pre[u];}
}void merge(int u,int v)
{pre[root(u)]=root(v);
}int main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int n,m;cin>>n>>m;for(int i=1;i<=n;i++) pre[i]=i;for(int i=1;i<=m;i++){int x,y;cin>>x>>y;merge(x,y);}for(int i=1;i<=n;i++) cnt[root(i)]++;vector<int>v;for(int i=1;i<=n;i++){if(cnt[i]!=0) v.push_back(cnt[i]);}sort(v.begin(),v.end());for(auto &i:v) cout<<i<<' ';return 0;}