信息学奥赛一本通 4149:【GESP2509七级】连通图 | 洛谷 P14077 [GESP202509 七级] 连通图

【题目链接】

ybt 4149:【GESP2509七级】连通图
洛谷 P14077 GESP202509 七级 连通图

【题目难度】:E

【题目考点】

1. 图论:连通分量

连通分量:无向图中极大的连通子图。

求图中连通分量数量的方法:

  • 深搜广搜
  • 并查集

2. 并查集

【解题思路】

本题可以作为求连通分量的模板题。

将图中每个连通分量可以看作一个顶点(这是"缩点"思路),设有 c n t cnt cnt个顶点,那么要想让这 c n t cnt cnt个顶点之间互相连通,形成一个连通图,需要添加的边数最少为 c n t − 1 cnt-1 cnt−1,形成树型结构(无环连通无向图)。

问题变为求图中连通分量的数量 c n t cnt cnt。

解法1:深搜广搜

尝试从每个未访问过的顶点出发进行深搜或广搜,标记已访问的顶点。成功开始搜索的次数为连通分量的数量

解法2:并查集

将每个连通分量当做一个集合。如果顶点A到顶点B有一条无向边,则顶点A、B在同一个集合中,将A、B所在的集合合并。遍历所有的边后,统计集合的数量即为连通分量的数量。

【题解代码】

解法1:深搜广搜求连通分量

  • 写法1:深搜求连通分量
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
vector<int> g[N];
int n, m, cnt;
bool vis[N];
void dfs(int u)
{
	vis[u] = true;
	for(int v : g[u]) if(!vis[v])
		dfs(v);
}
int main()
{
	int u, v;
	cin >> n >> m;
	for(int i = 1; i <= m; ++i)
	{
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i = 1; i <= n; ++i) if(!vis[i])
	{
		dfs(i);
		cnt++;
	}
	cout << cnt-1;
	return 0;
}
  • 写法2:广搜求连通分量
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
vector<int> g[N];
int n, m, cnt;
bool vis[N];
void bfs(int sv)
{
	queue<int> que;
	vis[sv] = true;
	que.push(sv);
	while(!que.empty())
	{
		int u = que.front();
		que.pop();
		for(int v : g[u]) if(!vis[v])
		{
			vis[v] = true;
			que.push(v);
		}
	}
}
int main()
{
	int u, v;
	cin >> n >> m;
	for(int i = 1; i <= m; ++i)
	{
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i = 1; i <= n; ++i) if(!vis[i])
	{
		bfs(i);
		cnt++;
	}
	cout << cnt-1;
	return 0;
}

解法2:并查集求连通分量

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, cnt, fa[N];
void init(int n)
{
	for(int i = 1; i <= n; ++i)
		fa[i] = i;
}
int find(int x)
{
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
	fa[find(x)] = find(y);
}
int main()
{
	int u, v;
	cin >> n >> m;
	init(n);
	for(int i = 1; i <= m; ++i)
	{
		cin >> u >> v;
		merge(u, v);
	}
	for(int i = 1; i <= n; ++i) if(fa[i] == i)
		cnt++;
	cout << cnt-1;
	return 0;
}
相关推荐
I_belong_to_jesus2 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Rabitebla3 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
码客-ygluu9 小时前
一个通用游戏数据服务器
c++·架构
another heaven9 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
YLCHUP12 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
xiaoye-duck12 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型
思麟呀12 小时前
背包DP(01背包+完全背包)
c++·算法
旖旎夜光14 小时前
【C++ 基础入门】C++11 新特性(中):右值引用、移动语义与完美转发
开发语言·c++·笔记·学习
ShineWinsu14 小时前
对于Qt:QTabWidget常见属性的解析
开发语言·数据库·c++·qt·浏览器·qtabwidget·标签页
俊俊几年的15 小时前
动态规划(Dynamic Programming)详解:从入门到 LeetCode Hot 100
linux·c++·算法·leetcode·嵌入式·动态规划·c