当前位置: 首页 > news >正文

蓝桥杯备考:图论之Prim算法

嗯。通过我们前面的学习,我们知道了,一个具有n个顶点的连通图,它的生成树包括n-1个边,如果边多一条就会变成图,少一条就不连通了

接下来我们来学一下把图变成生成树的一个算法

Prim算法,我们从任意一个结点开始构造最小生成树,先把离生成树最近的点拉进来,然后更新所有结点距离生成树的距离,然后再拉进来最近的点,然后再更新所有结点到这颗生成树的距离,一直到所有结点全部拉进来的时候,我们的算法就结束了

这里我们需要开两个数组,一个是dist数组来判断某个点距离生成树的距离,另一个是st数组,来判断某个点在不在生成树里

如图,我们把起始点加入进去了,接下来我们更新一下所有点离最小生成树的距离

我们还是找距离生成树最近的结点,如图,是5,我们把5拉进去

接下来把5标记上,然后更新所有点距离最小生成树的距离

然后继续找最小的,应该是2结点了

把2结点拉进去之后,我们再次更新dist数组,....如此往复,直到所有点都遍历完之后,我们的最小生成树也就构建完了;

话不多说我们来实现一下代码

我们先来实现一下邻接矩阵的代码;

这道题我们还要考虑一下连通不连通的情况

比如这张图,当我们用prim算法把2,1,5,4都加到生成树里的时候,3这个结点距离生成树的值还是无穷,就说明他不连通,没法找最小生成树

下面就是我们的代码

#include <iostream>
#include <cstring>
using namespace std;
const int N = 5010;
const int INF = 0x3f3f3f3f;
int dist[N];
bool st[N];
int edges[N][N];
int n, m;
int ret = 0;
int prim()
{
	dist[1] = 0;
	for (int i = 1; i <= n; i++)//循环把n个结点加入到生成树里面 
	{
		//1.找最近点
		int t = 0;
		for (int j = 1; j <= n; j++)
		{
			if (dist[j] < dist[t] && !st[j])
			{
				t = j;
			}
		}
		if (dist[t] == INF) return INF;//不连通
		//把最小结点加入到生成树里
		st[t] = true;
		ret += dist[t];
		//更新所有结点离最小生成树的距离
		for (int i = 1; i <= n; i++)
		{
			dist[i] = min(dist[i], edges[t][i]);
		}
	}
	return ret;
}
int main()
{
	cin >> n >> m;
	memset(dist, 0x3f, sizeof(dist));
	memset(edges, 0x3f, sizeof(edges));
	for (int i = 1; i <= m; i++)
	{
		int a, b, c; cin >> a >> b >> c;
		edges[a][b] = edges[b][a] = min(edges[a][b],c);
	}
	ret = prim();
	if (ret == INF) cout << "orz" << endl;
	else cout << ret << endl;





	return 0;
}

接下来,我们用邻接表实现一下这道题

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
const int N = 5010, INF = 0x3f3f3f3f;
vector <PII> path[N];
int dist[N];
bool st[N];
int ret = 0;
int n, m;
int prim()
{
	dist[1] = 0;
	for (int i = 1; i <= n; i++)
	{
		int t = 0;
		for (int j = 1; j <= n; j++)
		{
			if (dist[t] > dist[j] && !st[j])
			{
				t = j;
			}
		}
		if (dist[t] == INF) return INF;
		st[t] = true;
		ret += dist[t];
		for (auto &e : path[t])
		{
			int x = e.first, y = e.second;
			dist[x] = min(dist[x], y);
		}
	}
	return ret;
}
int main()
{
	memset(dist, 0x3f, sizeof(dist));
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
	{
		int x, y, z; cin >> x >> y >> z;
		path[x].push_back({ y,z });
		path[y].push_back({ x,z });
	}
	int r = prim();
	if (r == INF) cout << "orz" << endl;
	else cout << r << endl;






	return 0;
}

根据我们的代码可以看到,我们的prim算法时间复杂度是N²,如果结点很少边很多的话,我们用prim算法最合适

相关文章:

  • 2.3 滑动窗口专题:最大连续1的个数 III(LeetCode 1004)
  • PostgreSQL技术大讲堂 - 第82讲,主题:数据安全利器--密码安全策略构建
  • SpringBoot 和vue前后端配合开发网页拼图10关游戏源码技术分享
  • c++图论(一)之图论的起源和图的概念
  • 易语言模拟真人鼠标轨迹算法
  • 2025年渗透测试面试题总结-某四字大厂实习面试复盘 一面 三面(题目+回答)
  • Amazon Quantum Ledger Database (QLDB):革新数据可信记录的终极解决方案
  • (C语言)写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和(递归函数)
  • Axure设计之下拉多选框制作教程B(中继器)
  • 【Aioredis实战总结】Aioredis简介
  • 详解Flutter单线程模型,以及Flutter是如何通过单线程实现异步的
  • Go语言os标准库
  • SSA-随机森林分类预测matlab代码
  • 【Linux】https 协议
  • 用SpringBoot做一个web小案例配置拦截器判断登录状态
  • 某省政务信创案例:3阶段实施×5类工具链选型经验分享
  • 新型XCSSET恶意软件利用增强混淆技术攻击macOS用户
  • 【漫话机器学习系列】136.随机变量(Random Variable)
  • Windows系统中安装Rust工具链方法
  • VSCode + CMake
  • 最高法:依法惩治损害民营企业合法权益的串通投标行为
  • 大学2025丨苏大教授王尧:文科最大的危机是阐释世界的能力弱化
  • 国家统计局:4月全国城镇调查失业率为5.1%,比上月下降0.1个百分点
  • 从《缶翁的世界》开始,看吴昌硕等湖州籍书画家对海派的影响
  • 天问二号探测器顺利转入发射区,计划5月底择机发射
  • 陕西:未来一周高温持续,继续发布冬小麦干热风风险预警