最小生成树prim算法kruskal算法

news2024/11/25 17:23:52

最小生成树

在一个无向图中求一棵树(n-1条边,无环,连通所有点)而且这棵树的边的权和最小

prim(普利姆)算法

prim算法有叫加点法,我们先标定一个点,然后寻找与这个点相连的边的权值最小的点,不断重复此操作,直到所有的点都被连通,我们看下图
在这里插入图片描述
我们以洛谷P3366这道题为例来具体写一下代码

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>  // 用于memset
using namespace std;

const int N = 5010;    // 最大的点数
const int INF = 0x3f3f3f3f;    // 无穷大,表示两个点之间没有直接边
int n;      // n 表示点数
int mp[N][N];        // 邻接矩阵,存储所有边的权重
int dist[N];         // 存储其他点到当前最小生成树的最短距离
bool st[N];          // 用于标记每个点是否已经在生成树中

// 初始化函数,将邻接矩阵和其他辅助数组进行初始化
void init() {
    // 将邻接矩阵所有值设为无穷大INF,表示初始时没有任何边
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            mp[i][j] = INF;
        }
    }
    // 其他辅助数组清空
    memset(dist, 0x3f, sizeof dist);   // 将 dist 初始化为INF
    memset(st, 0, sizeof st);          // 将 st 数组全置为 false(初始时没有点在最小生成树中)
}

// Prim算法,计算最小生成树的权重总和
// 如果图不连通,返回 "orz"
int prim() {
    dist[1] = 0;  // 从第 1 个点开始,初始时距离设为0
    int res = 0;  // 存储最小生成树的总权重

    // 遍历 n 次,每次找一个点加入生成树
    for (int i = 0; i < n; i++) {
        int t = -1;  // t 用来存储当前距离生成树最近的点

        // 在所有未加入生成树的点中,找到距离最近的点 t
        for (int j = 1; j <= n; j++) {
            if (!st[j] && (t == -1 || dist[t] > dist[j])) {
                t = j;
            }
        }

        // 如果除了第一个点以外,某个点的距离为INF,说明图不连通
        if (i && dist[t] == INF) {
            cout << "orz" << endl;
            return 0;
        }

        // 如果该点不是第一个点,将其距离加入总权重
        if (i) {
            res += dist[t];
        }

        st[t] = true;  // 将点 t 标记为已加入生成树

        // 更新所有其他点到生成树的最短距离
        for (int j = 1; j <= n; j++) {
            dist[j] = min(dist[j], mp[t][j]);
        }
    }

    // 返回最小生成树的总权重
    return res;
}

int main() {
    int m;  // m 表示边数
    cin >> n >> m;  // 读入点数和边数

    init();  // 初始化邻接矩阵和其他辅助数组

    // 读入所有的边
    for (int i = 1; i <= m; i++) {
        int u, v, w;  // u, v 表示边的两个端点,w 表示权重
        cin >> u >> v >> w;

        // 如果这条边比之前存的边权小,则更新邻接矩阵
        if (mp[u][v] > w) {
            mp[u][v] = mp[v][u] = w;
        }
    }

    // 调用 Prim 算法,计算最小生成树的总权重
    int ans = prim();

    // 如果图连通,输出最小生成树的权重
    if (ans) {
        cout << ans << endl;
    }

    return 0;
}

kruskal(克鲁斯卡尔)算法

kruskal算法,又叫加边法,我们把所有点都列出来,然后一次把权值最短的边加上去,要注意加边之后不能形成环,我们看下图
在这里插入图片描述
还是同样的问题我们使用kruskal算法,我们主要是通过并查集来确保不会生成环

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>  // 用于 std::sort
using namespace std;

const int N = 5010;      // 最大点数
const int M = 2e5 + 10;  // 最大边数
const int INF = 0x3f3f3f3f;

int n, m;       // n 是点数,m 是边数
int p[N];       // 并查集的父节点数组

// 边结构体,存储一条边的信息(起点、终点、权重)
struct Edge {
    int a, b, w;

    // 运算符重载,用于边的排序,按边权升序排列
    bool operator< (const Edge& W) const {
        return w < W.w;
    }
} edges[M];

// 并查集查找操作,带路径压缩
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);  // 路径压缩
    return p[x];
}

// Kruskal 算法求解最小生成树
int kruskal() {
    // 首先对所有边按照权重排序
    sort(edges, edges + m);

    // 初始化并查集,每个点自成一个连通块
    for (int i = 1; i <= n; i++) p[i] = i;

    int res = 0, cnt = 0;  // res 保存最小生成树的权重总和,cnt 记录加入生成树的边数

    // 遍历所有边,按权重从小到大
    for (int i = 0; i < m; i++) {
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;

        // 查找两个端点所在的连通块
        a = find(a), b = find(b);

        // 如果两个连通块不同,则将它们合并
        if (a != b) {
            p[a] = b;  // 合并连通块
            res += w;   // 增加最小生成树的总权重
            cnt++;      // 增加计数,表示加入生成树的边数

            // 如果已经加入了 n - 1 条边,则生成树已经构建完成
            if (cnt == n - 1) break;
        }
    }

    // 如果连通块的数量小于 n - 1,说明图不连通
    if (cnt < n - 1) return INF;
    return res;  // 返回最小生成树的权重总和
}

int main() {
    cin >> n >> m;  // 输入点数和边数

    // 读入所有边
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        edges[i] = { u, v, w };  // 初始化每一条边
    }

    // 调用 Kruskal 算法计算最小生成树
    int ans = kruskal();

    // 如果图不连通,输出 "orz",否则输出最小生成树的总权重
    if (ans == INF) cout << "orz" << endl;
    else cout << ans << endl;

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2195185.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【鸿蒙学习】深入解析鸿蒙应用与元服务:含义、区别、应用场景及创建方法

文章目录 鸿蒙应用&#xff08;HarmonyOS App&#xff09;含义用于干什么优缺点 元服务&#xff08;Atomic Service&#xff09;含义用于干什么优缺点 鸿蒙应用与元服务的区别创建方法鸿蒙应用的创建元服务的创建 总结 随着科技的不断进步&#xff0c;操作系统也在不断迭代更新…

医院管理自动化:Spring Boot技术实践

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常适…

上传文件失败,请检查阿里云配置信息:[The specified bucket is not valid.

-- 十一假期结束 -- 去年今日此门中&#xff0c;人面挑花相应红。 -- 人面不知何处去&#xff0c;桃花依旧笑春风。

UART驱动学习三(TTY驱动部分源码解析)

目录 全局框架图一、tty_io.c 分析1. 关键数据结构和定义2. 文件操作结构体3. 初始化和注册4. 读写操作5. 挂起和恢复6. 信号处理7. 设备类8. 控制台通知9. 辅助函数10. 代码功能11. 带有注释的部分tty_io.c源码 二、tty_ldisc.c 分析1. 关键数据结构和定义2. 行规程操作函数3.…

从零开始打造华丽的国庆生活记录本地HTML网站

目录 目录 前言 准备工作 所需工具 文件夹结构 基础知识入门 HTML基础 CSS基础 JavaScript基础 步骤详解 1. 创建项目文件夹 2. 编写HTML文件 3. 添加CSS样式 4. 增加交互功能 5. 添加图片和视频 6. 美化网站 7. 实现响应式设计 8. 测试与优化 附加功能 创建…

Windows 搭建 Gitea

一、准备工作 1. 安装 Git&#xff1a;Gitea 依赖 Git 进行代码管理&#xff0c;所以首先需要确保系统中安装了 Git。 下载地址&#xff1a;https://git-scm.com/downloads/win 2. 安装数据库&#xff08;可选&#xff09; 默认情况下&#xff0c;Gitea 使用 SQLite 作为内…

【springboot】使用代码生成器快速开发

接上一项目&#xff0c;使用mybatis-plus-generator实现简易代码文件生成 在fast-demo-web模块中的pom.xml中添加mybatis-plus-generator、freemarker和Lombok依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator&…

Windows 11:如何轻松安装或卸载 Copilot 应用(多种方法)

起初&#xff0c;Copilot 是一个与 Windows 11 和 Windows 10 系统紧密结合的内置 AI 助手&#xff0c;能够通过回答问题、调整系统设置等功能来提高你的工作效率。 但从 Windows 11 24H2 开始&#xff0c;Copilot 功能已经从系统中剥离出来&#xff0c;成了一个基于 Microsoft…

【kubernetes】环境准备及K8S二进制安装【最新最全】

一,规划 1,架构 主节点(3台 master)+ 工作节点 (1台 node1) Pod网段: 10.0.0.0/16 Service网段: 10.255.0.0/16 实验环境规划: 操作系统:centos7.6 配置: 4Gib内存/6vCPU/100G硬盘 注意:也可以用4vCPU 网络:NAT 开启虚拟机的虚拟化: 2,K8S集群角色 Ip 主机名…

【嵌入式实时操作系统开发】智能家居入门4(FreeRTOS、MQTT服务器、MQTT协议、STM32、微信小程序)

前面已经发了智能家居入门的1、2、3了&#xff0c;在实际开发中一般都会使用到实时操作系统&#xff0c;这里就以FreeRTOS为例子&#xff0c;使用标准库。记录由裸机转到实时操作系统所遇到的问题以及总体流程。相较于裸机&#xff0c;系统实时性强了很多&#xff0c;小程序下发…

JavaSE——面向对象9.1:代码块详解

目录 一、静态代码块 二、构造代码块 三、局部代码块 四、总结 一、静态代码块 在《JavaSE——面向对象9&#xff1a;static、final关键字、代码块、单例模式》这篇文章中已经介绍过&#xff0c;静态代码块随着类的加载而加载&#xff0c;且只加载一次&#xff0c;这里不再…

【优选算法】---分治 归并排序

分治 归并排序 一、排序数组 / 归并排序的复习1、题目解析2、算法原理3、代码 二、逆序对的总数1、题目解析2、算法原理3、代码 三、计算右侧小于当前元素的个数1、题目解析2、算法原理3、代码 四、翻转对1、题目解析2、算法原理3、代码 一、排序数组 / 归并排序的复习 归并排…

Windows下Jenkins控制台中文乱码

问题描述 问题情况如下图&#xff1a; 环境信息 Windows 11 家庭中文版java 21.0.4 2024-07-16 LTSJenkins 2.452.3 解决方法 增加系统JAVA_TOOL_OPTIONS&#xff0c;并设置值为-Dfile.encodingGBK。 打开设置方法&#xff1a;桌面上右键点击“此电脑”图标&#xff0c;选…

软考高级之系统架构师之计算机硬件基础

概述 局部性原理是指在指定时间内&#xff0c;程序趋于在有限的内存区域内重复访问。通常将局部性分为空间局部性和时间局部性。空间局部性是指已访问过的内存地址附近的位置很可能被连续访问。时间局部性是指已访问过的内存地址在较短的时间内还可能被多次访问。 计算机执行…

请散户股民看过来,密切关注两件大事

明天股市要开市&#xff0c;不仅散户股民期盼节后股市大涨&#xff0c;上面也同样想在节后来上一个“开门红”。 为此&#xff0c;上面没休假&#xff0c;关起门来办了两件大事&#xff0c;这两天发布消息已提前预热了。 两件大事如下&#xff1a; 一是&#xff0c;上交所10…

柯桥生活口语学习之在化妆品店可以用到的韩语句子

화장품을 사고 싶어요. 我想买化妆品。 어떤 화장품을 원하세요? 您想买什么化妆品。 스킨로션을 찾고 있어요. 我想买化妆水&#xff0c;乳液。 피부 타입은 어떠세요? 您是什么皮肤类型&#xff1f; 민감성 피부예요. 我是敏感性皮肤。 평소에 쓰시는 제품은 뭐예…

【判断推理】逻辑基础

1.1 命题 用语言、符号或者式子表达的&#xff0c;可以判断真假的陈述句称为命题&#xff0c;一般写为 若p&#xff0c;则q 真命题&#xff1a;判断为真的语句假命题&#xff1a;判断为假的语句 eg1&#xff1a;小张是中国人&#xff08;若是小张&#xff0c;则是中国人&#…

【传感器技术】【9 温度测量,热电偶传感器,膨胀式温度传感器,压力测量,弹性式压力表】

上理考研周导师的哔哩哔哩频道 我在频道里讲课哦 目录 9.1、 温度概述 1&#xff0e; 温度与温标 2&#xff0e; 温度测量的主要方法和分类 9.2、 膨胀式温度传感器 1&#xff0e; 液体膨胀式 2&#xff0e; 固体膨胀式 3&#xff0e; 气体膨胀式 9.3、 热电偶传感器 1. …

Cesium的一些神奇概念及技术流程(1)

近期要深度研究Cesium。关于Cesium的用法、渲染流程等方面我看很多人都写过。我就写写其中一些可能平时用不到但是比较有趣的内容。因为边研究边写&#xff0c;所以会陆续出几集&#xff0c;然后合并在一起&#xff0c;欢迎大家跟踪。 我的这些文章不打算把一些基本概念展开解…