A92417题解
2026-07-15 11:03:45
发布于:浙江
17阅读
0回复
0点赞
基本思路:
思路一:本题要求最少加的边数,很明显可以并查集求集合数,加的边数就是答案。
思路二:用广搜或深搜,求连通块数,答案是。
如果不知道并查集,请在这里(ACGO)或这里(洛谷)学习并练习。
广搜在这里(ACGO),深搜这里(ACGO),或者这里(洛谷,深搜广搜都有)。
广搜代码(深搜广搜对比来说,个人喜欢用广搜):
#include <bits/stdc++.h>
using namespace std;
vector<int>ve[100010];//邻接表
bool vis[100010]={};//标记节点i是否被访问过
void bfs(int i){
queue<int>q;
q.push(i);
vis[i]=1;//标记该节点(不能少)
while (q.size()){
int l=q.front();
q.pop();
for (auto k:ve[l]){
if (vis[k]==0){
vis[k]=1;
q.push(k);
}
}
}//遍历该连通块(这不用解释了吧)
}
int main(){
int n,m;
cin>>n>>m;
for (int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);//邻接表存储图
}
int ans=0;
for (int i=1;i<=n;i++){
if (vis[i]==0){//没有被访问过,就代表是一个未被遍历的连通块
ans++;
bfs(i);//遍历这个连通块
}
}
cout<<ans-1;
return 0;
}
深搜代码:
#include <bits/stdc++.h>
using namespace std;
vector<int>ve[100010];
bool vis[100010]={};
void dfs(int i){
vis[i]=1;
for (auto k:ve[i]){
if (vis[k]==0){
dfs(k);
}
}//遍历该连通块(这不用解释了吧)
}
int main(){
int n,m;
cin>>n>>m;
for (int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
ve[u].push_back(v);
ve[v].push_back(u);//邻接表存储
}
int ans=0;
for (int i=1;i<=n;i++){
if (vis[i]==0){//没有被访问不,就代表是一个未被统计的连通块
ans++;
dfs(i);//遍历这个连通块
}
}
cout<<ans-1;
return 0;
}
并查集代码:
#include <bits/stdc++.h>
using namespace std;
int fa[100010];//记录点i集合根节点(本质是一棵树)
int find(int x){
if (fa[x]==x){
return x;
}
return fa[x]=find(fa[x]);//路径压缩优化
}//并查集find函数
void merge(int x,int y){
fa[find(x)]=find(y);
}//并查集merge函数
int main(){
int n,m;
cin>>n>>m;
for (int i=1;i<=n;i++){
fa[i]=i;
}//fa数组初始化
for (int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
if (find(x)!=find(y)){
merge(x,y);
}//如果x和y不在一个集合,将两个集合融合
}
set<int>s;
for (int i=1;i<=n;i++){
s.insert(find(i));//找有几个根节点
}
cout<<s.size()-1;//输出集合数-1
return 0;
}
希望对大家学习OI有帮助!
这里空空如也








有帮助,赞一个