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

ops/2025/3/18 10:05:24/

嗯。通过我们前面的学习,我们知道了,一个具有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算法最合适


http://www.ppmy.cn/ops/166737.html

相关文章

剑指 Offer II 087. 复原 IP

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20087.%20%E5%A4%8D%E5%8E%9F%20IP/README.md 剑指 Offer II 087. 复原 IP 题目描述 给定一个只包含数字的字符串 s &#xff0c;用以表示一个 IP 地址&#xf…

求职招聘网站源码,找工作招工系统,支持H5和各种小程序

招聘找活招工平台系统源码 招聘求职找工作软件 发布信息积分充值招聘系统,里面带纤细教程 功能介绍: 招工小程序主要针对工地招工工人找工作,工地可以发布招工信息,工人可以发布找活信息,招工信息可以置顶,置顶需要积分,积分可以通过签到、分享邀请好友、充值获取,后…

Flutter PopScope对于iOS设置canPop为false无效问题

这个问题应该出现很久了&#xff0c;之前的组件WillPopScope用的好好的&#xff0c;flutter做优化打算“软性”处理禁用返回手势&#xff0c;出了PopScope&#xff0c;这个组件也能处理在安卓设备上的左滑返回事件。但是iOS上面左滑返回手势禁用&#xff0c;一直无效。 当然之…

人工智能之数学基础:从线性变换理解矩阵范数和矩阵行列式

本文重点 我们已经学习了线性变换了,而且我们知道每一个线性变换都有一个矩阵,那么本文我们从线性变换的角度来理解矩阵范数和行列式。 矩阵范数 为什么要学习范数呢?因为范数是程度概念的推广,在矩阵理论的计算方法中,要讨论收敛问题和逼近问题,那么就需要引入向量和…

【redis】Jedis 操作 Redis 基础指令(下)

列表操作 lpush/rpush 和 lpop/rpop 将一个或者多个元素从左/右侧放入&#xff08;头/尾插&#xff09;到 list 中 依次头插 从 list 左/右侧取出元素&#xff08;即头/尾删&#xff09; public static void test1(Jedis jedis) { jedis.flushAll(); long n jedis.lpush(…

9种Python数据可视化方案,让财务数据焕发生命力

想象一下&#xff1a;你即将向董事会展示季度财务报告&#xff0c;面对的是一群已经看过无数PPT的高管。你是选择用普通的柱状图和折线图&#xff0c;还是用能够直观展示收入、支出、利润动态关系的交互式仪表板&#xff1f; 本文将通过一个完整的Python财务数据可视化案例&am…

使用 yum 命令安装 MariaDB 指南

文章目录 前言为什么开始选择 MariaDB&#xff1f;安装 MariaDB安装mariadb-server启动服务初始化配置设置开机启动配置远程访问权限 总结个人简介 前言 最近在 CentOS 7 上安装 MySQL 后启动遇到如下错误&#xff1a; systemctl start mysqldFailed to start mysqld.service…

C语言内存函数讲解

&#xff08;一&#xff09;memcpy函数 这是memcpy函数的说明。它的头文件是string.h。函数原型是 void* memcpy(void* destination, const void* source, size_t num) 第一个参数是一个指向一个字符串的指针&#xff0c;第二个也是一样的。而第三个参数是复制的字节个数。这…