C++算法:加权连通图的最小生成树(Prim)

news2024/11/17 11:44:21

文章目录

  • 前言
  • 一、Prim算法原理
  • 二、算法实现
    • 1、生成图
    • 2、Prim
  • 总结
    • 原创文章,未经许可,严禁转载


前言

在前文加权连通图的最小生成树(Kruskal)中已经用以边找点的方式实现最小生成树的生成。Prim算法也是一种常用的最小生成树算法,和Kruskal不同,Prim算法是以顶点找边实现的。


一、Prim算法原理

Prim算法的核心思想是:在加权连通图中,顶点的集合V,从图中某一顶点开始,得到子集M。重复得将连接到顶点集合M的权值最小的边加入到边集合,将新找到的顶点加入到顶点M集合,当M=V时,意味着所有顶点都已连通。也就得到了图的最小生成树。有加权连通图如下:
在这里插入图片描述
我们选中点A为起点,先将点A加入集合M。顶点A连接的权值最小的加为AB(4),我们选择这条边,将它加入边的集合,再将顶点B加入集合M。
在这里插入图片描述

然后,连接到M集合的权值最小的边是BC(8)和AH(8),可以任选一边,我们选择BC。同样将边加入边集合,顶点加入顶点集合。以此类推…
在这里插入图片描述

当满足了条件V=M后,就得到了此图的最小生成树。我们用C++代码实现它,下面代码还是用前文Kruskal已经使用的例子中的大部分代码,略有改动,再加上Prim算法的部分:

二、算法实现

我们需要有二个顶点集合,一个集合是已找到的顶点,另一个集合是未加入最小生成树的顶点。这样我们每次从已找到的顶点中的某一点出发,连接到未加入的顶点中权值最小的顶点。可以保证不会形成环,就无需判断是否形成环路。

1、生成图

代码如下(示例):

#include <iostream>
#include <vector>
#include <algorithm>
#include <bits/stdc++.h>

using namespace std;

typedef struct {
    int start;
    int end;
    int val;
}edge;

class Graph{
    private:
        int vertex;      //顶点数
        int** matrix;    //有向图关系矩阵
        int* sign;    //标记边所属集合
        vector<edge> edges;      //存储所有边
        vector<edge> mst;    //存储生成树的边
        int weight = 0;    //权重和

    public:
        Graph(const int n ,vector<vector<int>> &arr){
            vertex = n;           
            matrix = new int* [vertex];          //生成有向图关系矩阵
            sign = new int[vertex];               
            for (int i=0; i<vertex; i++) sign[i]=i;   //初始顶点集合标记为自身,表示图是各点独立的森林
            for (int i = 0; i < 9; ++i){
                matrix[i] = new int[9];
                for (int j=0; j<9; j++){
                    matrix[i][j] = 0;
                }
            }
            edge tmp;
            for (int i=0; i<15; ++i){          
                matrix[arr[i][0]][arr[i][1]] = arr[i][2];   //生成有向图矩阵
                matrix[arr[i][1]][arr[i][0]] = arr[i][2];   //反向也有边,prim算法需要
                tmp.start = arr[i][0];                      //生成所有边
                tmp.end = arr[i][1];
                tmp.val = arr[i][2];
                edges.push_back(tmp);
            }
        }

        ~Graph(){
            delete[] matrix;
            delete[] sign;

实际上与前文的图生成部分相比,只加了这一句matrix[arr[i][1]][arr[i][0]] = arr[i][2]; //反向也有边,prim算法需要因为是找边,边是双向的。所以要在矩阵中添加。

2、Prim

因为复用了前文的大量代码,所以实现此最小生成树的方式有点特殊。当然原理是一样的,就是代码有点奇怪的感觉,但是联系前文一起看可以更好地理解。代码如下(示例):

edge find_edge(list<int> va, list<int> v){
            int min=100, st, en;                              //假设权值最大为100
            for (auto i=v.begin(); i!=v.end(); i++){
                for (auto j=va.begin(); j!=va.end(); j++){
                    if (matrix[*i][*j] != 0 && matrix[*i][*j] < min){
                        st = *i, en = *j;
                        min = matrix[st][en];
                    }
                }
            }
            edge tmp;
            tmp.start=st, tmp.end=en, tmp.val=min;
            return tmp;
        }

        void prim(){
            list<int> va;  //所有顶点
            list<int> v;   //已加入的顶点
            for (int i=0; i<vertex; i++) va.push_back(i);  //生成所有顶点
            v.push_back(0);   //加入顶点0
            va.remove(0);
            while (va.size()){
                edge e = find_edge(va, v);
                mst.push_back(e);
                v.push_back(e.end);
                va.remove(e.end);
                weight += e.val;
            }
            for (int i=0; i<mst.size(); i++) cout << mst[i].start << " -- " << mst[i].end << endl; 
            cout << "The weight of the MST tree: " << weight <<endl;
        }

代码逻辑前面图示已经讲得很明白。va集合存储了所有的顶点,v是已加入生成树的顶点集合。不断循环遍历找出两个集合中相连顶点中权值最小的边,直到所有顶点都连通。要注意的顶点是加入v集合后,要在va集合中删除此顶点。


总结

最后的测试结果和Kruskal算法生成的略有不同,当然权值和是一样的。不然就至少有一个算法代码出错了,在此例中,只是生成边的顺序不同,实际上某些情况下,是很可能生成的树也不相同的,但二个算法生成的树的权值和肯定一样。

0 -- 3
3 -- 6
3 -- 1
6 -- 7
7 -- 8
8 -- 4
1 -- 5
5 -- 2
The weight of the MST tree: 36

这里是从顶点0开始生成的,实际上可以从任一个顶点开始。
Kruskal和Prim算法都是典型的贪心算法思想的应用,相对来说:Kruskal算法更适合边较少的稀疏图,Prim算法则更适用相反的情况,Kruskal算法的时间复杂度是O(ElogE),E是指边的数量,从这个复杂度就可以看出边越少越快。Prim算法的时间复杂度是O(ElogV),其中V是顶点的数量。

原创文章,未经许可,严禁转载

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

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

相关文章

python 妙笔生花

1.学习编程好处 最主要的好处就是,思考问题的方式变得更加具有逻辑性。 日常我们敲代码时,需要思考每一行的代码执行效果,它就需要认真设计每行代码可用性。如果在设计上发生错误,在代码执行时就会报错。还能做到 触类旁通。 古语有云: 有道无术,术可求,有术无道,止于术…

armbian可视化查看系统的使用情况

文章目录 armbian查看系统的使用情况在终端可视化查看方式htop简介htop安装和使用的步骤 在浏览器可视化查看方式 armbian查看系统的使用情况 在终端可视化查看方式 htop简介 htop’是一款任务管理器和系统监视工具&#xff0c;可在Armbian Linux中使用。它提供了比默认任务…

Python使用多线程操作tif影像和HBase数据库

本文介绍使用Python的多线程技术&#xff0c;提高happybase模块和gdal模块的效率&#xff0c;从tif格式的影像文件中读取数据&#xff0c;并将其存储到HBase数据库中。主要步骤包括&#xff1a; 准备工作&#xff1a;安装Python环境&#xff0c;安装happybase模块和gdal模块&a…

windows安装jdk1.8

1.下载jdk8 https://www.oracle.com/java/technologies/downloads/#java8-windows 百度网盘&#xff1a; 链接: https://pan.baidu.com/s/1qtVZ3Rsa1_n9XsFcXj07rA 提取码: yhwc 2.双击以后进行JDK的安装 操作前先在D盘保存java文件夹&#xff0c;里面新建jdk1.8.0_241文件…

AntDB 替换某省电信大数据平台的案例分享

亚信自研分布式数据库AntDB落地某省电信的案例分享 整体介绍 某省电信大数据分析平台&#xff0c;需要对BSS的三户、订单、实例等近10TB级的数据进行快速分析统计&#xff0c;每次分析的数据量最高达到5亿级别&#xff0c;同时需要向其它厂商开放这种实时的数据分析能力&…

Java-API简析_java.util.Currency类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131255544 出自【进步*于辰的博客】 其实我的【Java-API】专栏内的博文对大家来说意义是不大的。…

对象实例化空指针处理

1 问题 如何解决对象实例化空指针异常&#xff1f; 2 方法 首先创建一个package包&#xff0c;将其Menu类及相关代码放入其中&#xff0c;并在该package包下创建另一个类MenuItem&#xff0c;然后通过构造函数&#xff0c;写入需要运行的对象信息&#xff0c;最后在Menu类中用n…

leetcode 151. 反转字符串中的单词

2023.6.14 这道题全面考察了字符串的一些操作&#xff0c;这里我的思路是&#xff1a; 先对字符串进行空格去除操作&#xff0c;这里要注意一个细节&#xff1a;先用for循环去除连续空格&#xff0c;再用if判断开头和结尾的空格。再对没有异常空格的s 做一个反转操作。再对每一…

计算机网络基础知识(九)—— 什么是TelnetS?Telnet Over TLS

文章目录 01 | TelnetS02 | OpenSSL03 | 实现思路服务器处理流程客户端处理流程 04 | 代码实现服务端代码客户端代码编译过程 & 执行结果 前面学习了什么是HTTPS协议&#xff0c;了解了HTTPS的工作原理以及具体的工作流程&#xff0c;了解了HTTP协议和HTTPS协议之间的区别。…

SSM框架搭建

SSM环境搭建 1 IDE的话&#xff0c;我用的MyEcplise&#xff0c;如果用Ecplise的话&#xff0c;需要自行配置服务器。 首先&#xff0c;建一个Dynamic工程&#xff0c;需要注意的是一定要勾选上web.xml。 将Spring框架包、jstl包、standard包、common-logging包、aopallian…

系列十三、MongoDB聚合查询

一、概述 MongoDB聚合框架&#xff08;Aggregation Framework&#xff09;是一个计算框架&#xff0c;它可以&#xff1a; ①&#xff1a;作用在一个或者几个集合上; ②&#xff1a;对集合中的数据进行一系列的运算; ③&#xff1a;将这些数据转化为期望的形式; 从效果而言…

AIGC技术研究与应用 ---- 下一代人工智能:新范式!新生产力!(5 - AIGC 未来展望)

文章大纲 不可避免的职业替代AI 对人类思维的影响AIGC 的风险人工智能对齐 -- 价值学习 鲁棒适应参考文献与学习路径GPT 系列模型解析前序文章模型进化券商研报陆奇演讲多模态据预测,未来五年10%-30%的图片内容由AI参与生成,考虑到下一代互联网对内容需求的迅速提升,2030年A…

计算机网络管理 实验4(一) SNMP报文分析之验证SNMP协议的工作过程以及分析SNMP数据单元的格式

⬜⬜⬜ &#x1f430;&#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;(*^▽^*)欢迎光临 &#x1f7e7;&#x1f7e8;&#x1f7e9;&#x1f7e6;&#x1f7ea;&#x1f430;⬜⬜⬜ ✏️write in front✏️ &#x1f4dd;个人主页&#xff1a;陈丹宇jmu &am…

FPGA基础知识-门级建模

目录 学习目标 学习内容 1.门的类型 2.门延迟 学习时间 学习小结 学习目标 学习Verilog 提供的门级原语 理解门的实例引用、门的符号以及andor&#xff0c;bufnot类型的门的真值表 学习如何根据电路的逻辑图来生成verilog描述 讲述门级设计中的上升、下降和关断延迟 …

【论文解读系列】Blip-2:引导语言图像预训练具有冻结图像编码器和大型语言模型

Blip-2 BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models BLIP-2&#xff1a;引导语言图像预训练具有冻结图像编码器和大型语言模型 (0) 总结&实测 总结&#xff1a;blip-2 最大的贡献在于&#xff0c;提出了…

跨境电商社交媒体:选择合适的平台

正如您在使用社交媒体的九种方法中了解到的那样&#xff0c;跨境电商优先考虑社交媒体营销可能会更有利可图。有数十个平台可供选择&#xff0c;每个平台都迎合了具有不同兴趣、特征和位置的独特受众。 那么您应该关注哪个社交媒体平台以及如何以最大效率工作&#xff1f; 目…

【Vue全家桶高仿小米商城】——(三)VueCli4.0安装和使用

文章目录 第三章&#xff1a;VueCli4.0安装和使用一、VueCli4.0安装&#xff1a;二、创建Vue项目方式一 使用脚本搭建方式二 使用UI界面搭建 三、安装依赖方式一 Vue脚手架图形界面安装方式二、命令行安装 四、Vue DevTools安装使用两种安装方式&#xff1a; 第三章&#xff1a…

Linux权限解析

一、Linux用户分类 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受限制 普通用户&#xff1a;在linux下做有限的事情。 超级用户的命令提示符是“#”&#xff0c;普通用户的…

6.6面向对象继承

2. 面向对象特征二&#xff1a;继承(Inheritance) 2.1 继承的概述 说到继承我们会想到什么 在Java面向对象程序设计中的继承&#xff0c;多个类中存在相同属性和行为时&#xff0c;将这些相同的内容抽取到单独一个类&#xff08;父类&#xff09;中&#xff0c;然后所有的类继…

【备战秋招】每日一题:4月15日美团春招第二题:题面+题目思路 + C++/python/js/Go/java带注释

为了更好的阅读体检&#xff0c;为了更好的阅读体检&#xff0c;&#xff0c;可以查看我的算法学习博客第二题-分糖果 在线评测链接:P1236 题目内容 某天&#xff0c;塔子哥去商店买了两种不同口味的糖果&#xff0c;分别买了 a 个和 b 个。当他回到家时&#xff0c;他发现他…