Prim算法简易教程(~简单易懂,附最详细注释代码)
文章目录
- 1 最小生成树(Minimum Spanning Tree,MST)
- 2 Prim算法
- 2.1 简介
- 2.2 具体步骤
- 2.3 算法示例图
- 2.4 算法实现
- 2.5 算法分析
- 2.6 测试
1 最小生成树(Minimum Spanning Tree,MST)
在一给定的无向图G=(V,E)G = (V, E)G=(V,E) 中,(u,v)(u, v)(u,v)代表连接顶点uuu 与顶点 vvv 的边,而 w(u,v)w(u, v)w(u,v) 代表此边的权重,若存在 TTT 为 EEE 的子集且为无循环图,使得 w(T)w(T)w(T) 最小,则此 TTT 为 GGG 的最小生成树,因为TTT是由图GGG产生的。
最小生成树其实是最小权重生成树的简称。我们称求取该生成树的问题成为最小生成树问题。一个连通图可能有多个生成树。当图中的边具有权值时,总会有一个生成树的边的权值之和小于或者等于其它生成树的边的权值之和。广义上而言,对于非连通无向图来说,它的每一连通分量同样有最小生成树,它们的并被称为最小生成森林。以有线电视电缆的架设为例,若只能沿着街道布线,则以街道为边,而路口为顶点,其中必然有一最小生成树能使布线成本最低。
如图,这个是一个平面图,图中黑色线描述的就是最小生成树,它的权值之和小于其他的生成树。
那么,我们如何来求最小生成树呢,由最小生成树的定义我们可以知道构建最小生成树是可以利用贪心算法去实现的,我们接下来介绍的两种算法也都是利用贪心算法去求得MSTMSTMST的。因为贪心算法的策略就是在每一步尽可能多的选择中选择最优的,在当前看是最好的选择,这种策略虽然一般不能在全局中寻找到最优解,但是对于最小生成树问题来说,它的确可以找到一颗权重最小的树。
2 Prim算法
2.1 简介
普里姆算法(Prim’s algorithm),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克发现;并在1957年由美国计算机科学家罗伯特·普里姆独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。(来源于维基百科)
2.2 具体步骤
Prim算法是利用贪心算法实现的,我们确定根节点,从这个结点出发。普里姆算法按照以下步骤逐步扩大树中所含顶点的数目,直到遍及连通图的所有顶点。下面描述我们假设N=(V,E)N=(V,E)N=(V,E)是连通网,TETETE是NNN上最小生成树中边的集合。
① U={u0}(u0∈V),TE={}U=\{u_0\}(u_0∈V) ,TE= \{\}U={u0}(u0∈V),TE={}。
② 在所有u∈U,v∈(V−U)u∈U,v∈(V-U)u∈U,v∈(V−U)的边(u,v)∈E(u,v)∈E(u,v)∈E找到一条权值最小的边(u0,v0)(u_0,v_0)(u0,v0)并入集合TETETE,同时v0v_0v0并入集合UUU。
③ 重复②步骤,知道U=VU=VU=V为止。
此时TETETE中必有n−1n-1n−1条边,则T=(V,TE)T=(V,TE)T=(V,TE)即为我们求得的NNN的最小生成树。
2.3 算法示例图
2.4 算法实现
我们如果对Dijkstra算法很熟悉的话,Prim算法也很好实现了,它们都是利用了一样的思路,但却不相同。我们用利用lowcostlowcostlowcost数组来表示到集合中最近的距离,用closestclosestclosest数组来表示最小生成树的边。怎么来表示呢?我们用顶点来形容边,也就是说我们要求的就是closetclosetcloset数组。其中closest[i]closest[i]closest[i]表示的值就是与iii顶点相邻边的顶点序号。具体看代码(附带打印最小生成树代码)。
/*
*邮箱:unique_powerhouse@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h> //POJ不支持#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pairusing namespace std;const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e3;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//int n,m;//图的大小和边数。
int graph[maxn][maxn];//图
int lowcost[maxn],closest[maxn];//lowcost[i]表示i到距离集合最近的距离,closest[i]表示i与之相连边的顶点序号。
int sum;//计算最小生成树的权值总和。
void Prim(int s){//初始化操作,获取基本信息。rep(i,1,n){if(i==s)lowcost[i]=0;elselowcost[i]=graph[s][i];closest[i]=s;}int minn,pos;//距离集合最近的边,pos代表该点的终边下标。sum=0;rep(i,1,n){minn=inf;rep(j,1,n){//找出距离点集合最近的边。if(lowcost[j]!=0&&lowcost[j]<minn){minn=lowcost[j];pos=j;}}if(minn==inf)break;//说明没有找到。sum+=minn;//计算最小生成树的权值之和。lowcost[pos]=0;//加入点集合。rep(j,1,n){//由于点集合中加入了新的点,我们要去更新。if(lowcost[j]!=0&&graph[pos][j]<lowcost[j]){lowcost[j]=graph[pos][j];closest[j]=pos;//改变与顶点j相连的顶点序号。}}}cout<<sum<<endl;//closest数组就是我们要的最小生成树。它代表的就是边。
}
void print(int s){//打印最小生成树。int temp;rep(i,1,n){//等于s自然不算,故除去这个为n-1条边。if(i!=s){temp=closest[i];cout<<temp<<"->"<<i<<"边权值为:"<<graph[temp][i]<<endl;}}
}
int main(){//freopen("in.txt", "r", stdin);//提交的时候要注释掉IOS;while(cin>>n>>m){memset(graph,inf,sizeof(graph));//初始化。int u,v,w;//临时变量。rep(i,1,m){cin>>u>>v>>w;//视情况而论,我这里以无向图为例。graph[u][v]=graph[v][u]=w;}//任取根结点,我这里默认取1.Prim(1);print(1);//打印最小生成树。}return 0;
}
2.5 算法分析
对于此算法,我们图中有nnn个顶点,则第一个进行初始化的循环语句的频度为nnn,第二个循环语句的频度为nnn,但其中第二个循环中有两个内循环:第一个是在lowcostlowcostlowcost中求最小值,其频度为nnn,第二个是重新选择具有最小权值的边,频度为nnn,由此我们可知Prim算法的时间复杂度为O(n2)O(n^2)O(n2),与图中的边数无关,故十分适合于稠密图。
2.6 测试
我们用示例来测试:
7 11
1 2 7
1 4 5
2 4 9
2 3 8
2 5 7
4 5 15
4 6 6
6 7 11
5 6 8
5 7 9
3 5 5
测试结果如图:
Prim算法简易教程(~简单易懂,附最详细注释代码)相关推荐
- 灰狼优化算法--简单易懂附python代码
ps:本博文为个人理解,如有错误请不吝赐教 本博文部分引用了 https://blog.csdn.net/haha0332/article/details/8880591*0 1.算法原理:简单的讲, ...
- Kruskal算法简易教程(附最全注释代码实现)
文章目录 1 简介 2 构造过程 3 示例 4 算法实现 5 算法分析 6 测试 1 简介 Kruskal算法是一种用来查找最小生成树(MSTMSTMST)的算法,由Joseph Kruskal在19 ...
- 标准BP算法matlab实现,简单易懂
机器学习的实验课要求自编写一份简易的标准BP(神经网络)算法,我用matlab基本实现了,现将自己的思想记录下来,方便自己以后重温.话不多说,让我们进入正题 调用matlab的神经网络算法解决具体问题 ...
- c语言教程——简单易懂
一.c语言教程入门 C 语言是一种广泛使用的计算机语言,它与 Java 编程语言一样普及,二者在现代软件程序员之间都得到广泛使用. 当前最新的 C 语言标准为 C18 ,在它之前的 C 语言标准有 C ...
- RSA算法原理(简单易懂)
1. 什么是RSA RSA算法是现今使用最广泛的公钥密码算法,也是号称地球上最安全的加密算法.在了解RSA算法之前,先熟悉下几个术语 根据密钥的使用方法,可以将密码分为对称密码和公钥密码 对称密码 ...
- 迪克斯特拉算法(Dijkstra 最短路算法)(简单易懂)
Dijkstra 最短路算法 上周我们介绍了神奇的只有五行的 Floyd 最短路算法,它可以方便的求得任意两点的最短路径,这称为"多源最短路".本周来来介绍指定一个点(源点)到其余 ...
- bat批处理零基础教程-简单易懂幽默风趣-①
本文章所有文字.代码.标题等均有MouBai00001编写,均无抄袭,搬运等行为! 此文章仅在CSDN上发布过,如您在其他论坛看到此文章,均为抄袭! ①.批处理是什么 批处理,一种Windows简化脚 ...
- dijkstra算法详解—简单易懂
文章目录 1 简介 2 算法思想与原理 3 具体步骤 4 动态展示 5 代码实现(以邻接矩阵为例) 5.1 基本数据 5.2 初始化 5.3 dijkstra算法核心 5.4 主函数与头文件等 6 拓 ...
- ==与equals的区别(四个例子简单易懂)附jvm简图
目录 1.概述 1.==解析 2.equals解析 3.源码图解 2.例子 1.jvm内存简图 2.第一个"=="比较的解析 3.第二个"=="比较的解析 ...
最新文章
- 为什么蚂蚁永远不会堵车?
- 为什么地磅的读数有进制么_谈谈二进制(三)——位运算及其应用
- android4.0 编译报错 Xmx2048m错误 .
- GDCM:gdcm::ByteValue的测试程序
- vlc框架流程解析(转)
- 100多本python书,免费电子版下载
- 《JavaScript DOM编程艺术》笔记
- ACM学习历程—51NOD 1685 第K大区间2(二分 树状数组 中位数)
- imageset matlab,如何以imageSet或imageDataStore的形式向MATLAB中的BagOfFeatures()函數提供輸入?...
- Nodejs 英雄管理系统
- Android设为系统默认的短信应用
- 听音乐学英语之- I Need to Wake Up 奥斯卡获奖单曲:关注全球变暖
- Mysql中Check约束无效的原因以及解决方法
- 2.1简单计算问题的求解
- 想进外企你应该知道的七大基本面试知识
- springboot整合mybatis错误 Invalid bound statement (not found): 解决办法
- 深度学习论文: Compounding the Performance Improvements of Assembled Techniques in a CNN及其PyTorch实现
- php cdr,cdr文件用什么打开
- 品《阿里巴巴大数据实践-大数据之路》一书(下)
- react native Android端保持APP后台运行--封装 Headless JS