prim算法解决最小生成树问题

2023-11-17

刚好这次又遇到了prim算法,就做了下整理(可以参考《数据结构与算法分析c++描述》这本书,个人而言,很经典),并把以前写的代码也整理了一下,做下分享,同时也加深下自己的理解。

prim算法是解决最小生成树问题的一个很好的算法。此算法是是将点集合中的点一步步加到树中,在每一步中,都要把一个节点当作根本并往上加边,这样也就把相关联的顶点增加到树上了。这样说有点枯燥和难以理解,下面借用一个例子进行详细讲解:

(1)如下图所示,是一个无向图,所有点的点集为S={v1,v2,v3,v4,v5,v6,v7},带加入点的集合G={}:


(2)首先,我们将这个图的所有边先隐藏掉,这里我们选择点“v1”作为起点,此时点集G为{v1},接下来的规则是在后续的步骤中,在G中的点和S-G中的点的边中选择最短的 边添加进去,此时情况如下图所示:


(3)在“v1”的所有邻接点中找到路径长度最短的一个,即“v4”,此时两点点长度为1,将“v1”和“v4”连接起来,此时点集G为{v1,v4},如下图所示:


(4)在点集{v1,v4}中找到与v1、v4临接的点中边的长度最短的一个,即点v2(其实v4也是可以的,这里我们就选择v2),此时点集G为{v1,v2,v4},如下图所示:


(5)按照(2)中提到的规则应该将点v3添加到G中,此时G为{v1,v2,v3,v4},如下图:


(6)此时选择将点v7添加到G中,则G={v1,v2,v3,v4,v7},如下图:


(7)此时选择将点v6添加到G中,则G={v1,v2,v3,v4,v6,v7},如下图:


(8)最后将点v5添加到G中,则G={v1,v2,v3,v4,v5,v6,v7},如下图:


从上面的示例中可以可以看出,在prim算法中,我们可以对每一个顶点保留值dv和Pv以及一个指标,表示该顶点是known还是unknown。在这里,dv是连接到已知顶点的最短边的权,则Pv则是导致dv改变的最后的顶点。在每个阶段,prim算法将会选择一个顶点v,它在所有的unknown顶点中具有最小的dv,同时算法将声明s(s是与v相连的这个拥有最小dv的另一个点,注意这个点s一定是known的)到v的最短路径是known的。在这个顶点v被选择之后,对于每一个与v邻接的且是unknown的点w,dw=min(dw,Cw,v)。其中Cw,v代表此时点w和v直接的距离。

对于上面的例子,下面我们用表来刻画相应的转化状态:

(1)表的初始状态如下:


(2)选取点v1,同时更新v2、v3、v4,结果如下图:


(3)通过比较可知,此时v4的dv最小,故选取点v4,同时更新与v4邻接的点(其中v1除外,因为v1已经是known),在这里主要需要注意的是v3的值,在更新的时候明显Cv3,v4<Cv1,v3,所以更新v3处的值,如下图所示:


(4)此时在比较中,会发现v2和v3的值是一样的,那么这里就选取v2(当然,选取v3也是可以的),然后按照相应的规则进行更新,如下图所示:


(5)此时选择v3,并进行相应的更新,如下图:


(6)此时选择v7,并进行相应的更新,如下图:


(7)此时选择v6,并进行相应的更新,如下图:


(7)最优将v5置为true,结束:


对于上述的算法描述过程,对于v,dv,pv,known这些变量的表示方法,可以根据不同的需要进行调整。

对于prim算法,由于是在无向图上进行的,因此当编写代码的时候要记住把每一条边都放到两个邻接表中。在不用堆时,运行时间为O(|v|^2),它对于稠密的图来说是最优的。使用二叉堆时,运行时间是O(|E|log|V|),对于稀疏的图是一个好的界。

下面给出一个具体的实现,在实现中我采用了有限队列进行求解(二叉堆的一种具体形式),代码如下:

[cpp]  view plain  copy   在CODE上查看代码片 派生到我的代码片
  1. #include<iostream>  
  2. using namespace std;  
  3. #include<vector>  
  4. #include<string>  
  5. #include<list>  
  6. #include<queue>  
  7.   
  8. struct node   //为了便于prim算法  
  9.     {  
  10.         int vertexNum;  
  11.         int key;  
  12.         node(int num=0,int k=INT_MAX):vertexNum(num),key(k){}  
  13.         friend bool operator<(const node &n1,const node &n2)  
  14.         {  
  15.             return n1.key<n2.key;  
  16.         }  
  17.         friend bool operator>(const node &n1,const node &n2)  
  18.         {  
  19.             return n1.key>n2.key;  
  20.         }  
  21.     };  
  22. struct edgeNode  
  23. {  
  24.     int oneVertex;  
  25.     int otherVertex;  
  26.     int edgeWeight;  
  27.     edgeNode(int oneNum=0,int otherNum=0,int eWeight=0):oneVertex(oneNum),otherVertex(otherNum),edgeWeight(eWeight){}  
  28.     friend bool operator>(const edgeNode &edge1,const edgeNode &edge2)  
  29.     {  
  30.         return edge1.edgeWeight>edge2.edgeWeight;  
  31.     }  
  32. };  
  33. class UDGraph  
  34. {  
  35.     struct Edge  
  36.     {  
  37.         int nDestVertex;  
  38.         int edgeWeight;  
  39.         Edge(int num,int weight):  
  40.         nDestVertex(num),edgeWeight(weight){}  
  41.     };  
  42. private:  
  43.     struct vertex  
  44.     {  
  45.         string vertexName;  
  46.         list<Edge> adjEdges;  
  47.         vertex(const string &name=NULL,list<Edge> adj=list<Edge>()):vertexName(name),adjEdges(adj){}  
  48.     };  
  49. public:  
  50.     UDGraph():m_vertexList(NULL){}  
  51.     ~UDGraph()  
  52.     {  
  53.         for(int i=0;i<m_vertexList.size();i++)  
  54.         {  
  55.             m_vertexList[i].adjEdges.clear();  
  56.         }  
  57.         m_vertexList.clear();  
  58.     }  
  59.     bool insertVertex(const string &v)  
  60.     {  
  61.         int index=getVertexIndex(v);  
  62.         if(-1!=index)  
  63.             return false;  
  64.         m_vertexList.push_back(vertex(v));  
  65.     }  
  66.     bool insertEdge(const string &v1,const string &v2,int weight=0)  
  67.     {  
  68.         int index1=getVertexIndex(v1);  
  69.         int index2=getVertexIndex(v2);  
  70.         if(-1==index1)  
  71.             return false;  
  72.         if(-1==index2)  
  73.             return false;  
  74.         m_vertexList[index1].adjEdges.push_back(Edge(index2,weight));  
  75.         m_vertexList[index2].adjEdges.push_back(Edge(index1,weight));  
  76.         return true;  
  77.     }  
  78.     int getVertexNum() const  
  79.     {  
  80.         return m_vertexList.size();  
  81.     }  
  82.     bool removeEdge(const string &v1,const string &v2)  
  83.     {  
  84.         int index1=getVertexIndex(v1);  
  85.         int index2=getVertexIndex(v2);  
  86.         if(-1==index1)  
  87.             return false;  
  88.         if(-1==index2)  
  89.             return false;  
  90.         auto itr1=m_vertexList[index1].adjEdges.begin();  
  91.         auto itr2=m_vertexList[index2].adjEdges.begin();  
  92.         bool flag1=false,flag2=false;  
  93.         for(;itr1!=m_vertexList[index1].adjEdges.end();++itr1)  
  94.         {  
  95.             if(itr1->nDestVertex==index2)  
  96.             {  
  97.                 m_vertexList[index1].adjEdges.erase(itr1);  
  98.                 flag1=true;  
  99.                 break;  
  100.             }  
  101.         }  
  102.         for(;itr2!=m_vertexList[index2].adjEdges.end();++itr2)  
  103.         {  
  104.             if(itr2->nDestVertex==index1)  
  105.             {  
  106.                 m_vertexList[index1].adjEdges.erase(itr2);  
  107.                 flag2=true;  
  108.                 break;  
  109.             }  
  110.         }  
  111.         return flag1&&flag2;  
  112.     }  
  113.     void Prim(const string &v,vector<int> &prev,vector<node> &node_vec)  
  114.     {  
  115.         priority_queue<node,vector<node>,greater<node> > nodeQueue;  
  116.         node_vec.resize(m_vertexList.size());  
  117.         for(int i=0;i<node_vec.size();i++)  
  118.         {  
  119.             node_vec[i].vertexNum=i;  
  120.             node_vec[i].key=INT_MAX;  
  121.         }  
  122.         int beginIndex=getVertexIndex(v);  
  123.         node_vec[beginIndex].key=0;  
  124.         vector<bool> visited(m_vertexList.size(),false);  
  125.         prev.assign(m_vertexList.size(),-1);  
  126.         visited[beginIndex]=true;  
  127.         nodeQueue.push(node_vec[beginIndex]);  
  128.         while(!nodeQueue.empty())  
  129.         {  
  130.             node vertexNode=nodeQueue.top();  
  131.             nodeQueue.pop();  
  132.             /*if(visited[vertexNode.vertexNum]) 
  133.                 continue;*/  
  134.             visited[vertexNode.vertexNum]=true;  
  135.             list<Edge> edgeList=m_vertexList[vertexNode.vertexNum].adjEdges;  
  136.             for(auto it=edgeList.begin();it!=edgeList.end();++it)  
  137.             {  
  138.                 if(!visited[it->nDestVertex]&&it->edgeWeight<node_vec[it->nDestVertex].key)  
  139.                 {  
  140.                     prev[it->nDestVertex]=vertexNode.vertexNum;  
  141.                     node_vec[it->nDestVertex].key=it->edgeWeight;  
  142.                     node_vec[it->nDestVertex].vertexNum=it->nDestVertex;  
  143.                     nodeQueue.push(node_vec[it->nDestVertex]);  
  144.                 }  
  145.             }  
  146.         }  
  147.     }  
  148.     void printPathResult(const vector<int> &prev) const  
  149.     {  
  150.         for(int i=1;i<prev.size();i++)  
  151.         {  
  152.             cout << "(" << getName(i) << "," << getName(prev[i]) << ")" << endl;  
  153.         }  
  154.     }  
  155.     int PrimWeightResult(const vector<node> &node_vec) const  
  156.     {  
  157.         int edgeSum=0;  
  158.         for(int i=0;i<node_vec.size();i++)  
  159.             edgeSum+=node_vec[i].key;  
  160.         return edgeSum;  
  161.     }  
  162.   
  163.     void setTreeNode(const string &name)  
  164.     {  
  165.         treeNode=getVertexIndex(name);  
  166.     }  
  167. private:  
  168.     vector<vertex> m_vertexList;  
  169.     static int counter;  //用来为深度优先搜索时为点排序号  
  170.     static int treeNodeNum;   //记录根节点的分支个数  
  171.     static int treeNode;   //记录根节点的编号  
  172.     int getVertexIndex(const string &name) const  
  173.     {  
  174.         for(int i=0;i<m_vertexList.size();i++)  
  175.         {  
  176.             if(name==m_vertexList[i].vertexName)  
  177.                 return i;  
  178.         }  
  179.         return -1;  
  180.     }  
  181.     string getName(int index) const   
  182.     {  
  183.         return m_vertexList[index].vertexName;  
  184.     }  
  185.     bool compare(const node &n1,const node &n2)  
  186.     {  
  187.         return n1.key<n2.key;  
  188.     }  
  189.     priority_queue<edgeNode,vector<edgeNode>,greater<edgeNode> > getEdgeNodes() const   
  190.     {  
  191.         priority_queue<edgeNode,vector<edgeNode>,greater<edgeNode> > edgeQueue;  
  192.         vector<int> visit1(m_vertexList.size(),false);  
  193.         vector<int> visit2(m_vertexList.size(),false);  
  194.         for(int index=0;index<m_vertexList.size();index++)  
  195.         {  
  196.             list<Edge> adjList=m_vertexList[index].adjEdges;  
  197.             for(auto it=adjList.begin();it!=adjList.end();++it)  
  198.             {  
  199.                 if(visit1[index]&&visit2[it->nDestVertex])  
  200.                     continue;  
  201.                 else  
  202.                 {  
  203.                     edgeQueue.push(edgeNode(index,it->nDestVertex,it->edgeWeight));  
  204.                 }  
  205.             }  
  206.             visit1[index]=true;  
  207.             visit2[index]=true;  
  208.         }  
  209.         return edgeQueue;  
  210.     }  
  211.     int find(const vector<int> &prev,int x) const  
  212.     {  
  213.         if(prev[x]<0)  
  214.             return x;  
  215.         else  
  216.             return find(prev,prev[x]);  
  217.     }  
  218.     void unionSets(vector<int> &prev,int root1,int root2)  
  219.     {  
  220.         prev[root1]=root2;  
  221.     }  
  222.   
  223. };  
  224. int UDGraph::counter=1;  
  225. int UDGraph::treeNodeNum=0;  
  226. int UDGraph::treeNode=0;  
  227. int main()  
  228. {  
  229.     UDGraph graph;  
  230.     graph.insertVertex("v1");  
  231.     graph.insertVertex("v2");  
  232.     graph.insertVertex("v3");  
  233.     graph.insertVertex("v4");  
  234.     graph.insertVertex("v5");  
  235.     graph.insertVertex("v6");  
  236.     graph.insertVertex("v7");  
  237.     graph.insertEdge("v1","v2",2);  
  238.     graph.insertEdge("v1","v3",4);  
  239.     graph.insertEdge("v1","v4",1);  
  240.     graph.insertEdge("v2","v4",3);  
  241.     graph.insertEdge("v2","v5",10);  
  242.     graph.insertEdge("v3","v6",5);  
  243.     graph.insertEdge("v3","v4",2);  
  244.     graph.insertEdge("v4","v5",7);  
  245.     graph.insertEdge("v4","v6",8);  
  246.     graph.insertEdge("v4","v7",4);  
  247.     graph.insertEdge("v5","v7",6);  
  248.     graph.insertEdge("v6","v7",1);  
  249.     vector<int> prev;  
  250.     vector<node> node_vec;  
  251.     vector<int> dist;  
  252.     graph.Prim("v1",prev,node_vec);  
  253.     graph.printPathResult(prev);  
  254.     int edgeSum=graph.PrimWeightResult(node_vec);  
  255.     cout << "最小生成树的路径权重之和为:" << edgeSum << endl;  
  256.   
  257.     return 0;  
  258. }  
好了,这次就分享这么多了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

prim算法解决最小生成树问题 的相关文章

随机推荐

  • vs中nuget包引用感叹号解决

    移除其中一个包引用 然后重新再nuget中搜索 然后在添加进来 其他的有感叹号的nuget包引用也自动刷新包了 就解决了
  • +-字符串(简单贪心)

    字符串 时间限制 1000 ms 内存限制 65535 KB 难度 1 描述 Shiva得到了两个只有加号和减号的字符串 字串长度相同 Shiva一次可以把一个加号和它相邻的减号交换 他想知道最少需要多少次操作才能把第一个字符串变换成第二个
  • python 安装第三方库imblearn

    首先把自己的numpy scikit learn scipy卸载掉 然后执行 pip install imblearn i http pypi douban com simple trusted host pypi douban com 如
  • MySQL学习笔记

    文章目录 一 数据库概述及数据准备 SQL DB DBMS 表 table SQL语句分类 导入数据 查看表结构 查看表中的数据 二 常用命令 查看MySQL版本 创建数据库 查询当前使用的数据库
  • ChatGPT/InstructGPT详解

    前言 GPT系列是OpenAI的一系列预训练文章 GPT的全称是Generative Pre Trained Transformer 顾名思义 GPT的目的就是通过Transformer为基础模型 使用预训练技术得到通用的文本模型 目前已经
  • sublime主题配色

    ignored packages Vintage theme Default Dark sublime theme dark theme Default sublime theme light theme Adaptive sublime
  • 【华为OD机试】生日礼物【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 小牛的孩子生日快要到了 他打算给孩子买蛋糕和小礼物 蛋糕和小礼物各买一个 他的预算不超过x元 蛋糕cake和小礼物gift都有多种价位的可供选择 请返回小牛共有多少种
  • 【vue3】watchEffect只监听一次的方法

    import watchEffect from vue let data ref watchEffect gt console log data value 要利用data value执行的操作 而且还必须在watchEffect里面执行
  • 记录错误:con not perform the following tasks

    Ubuntu系统下安装软件出现报错 con not perform the following tasks TOC 检查软件源 实在不行改为国内源 或者等待网络再次下载
  • Bootstarp4 设计网页轮播组件

    很多网站都有广告轮播功能 可使用bootstrap4中的carousel组件非常简单的实现 目录 下载bootstrap4 轮播功能实现 简单实现轮播组件 增加标识图标 增加标题和说明 切换淡入淡出 设置数据间隔 总结 下载bootstra
  • 基于微信云开发实现电影推荐小程序

    一 项目背景 项目名称为柚子电影 此小程序的目的是为了给大家推荐电影 与其他的售票等小程序不同 二 性能需求 我的影单的增加 删除和查询 电影详情页面的完整实现 对小程序的各个方面 电影推荐 电影详情 用户授权 影院查询 影院位置 用户登录
  • Scala(一):概述&变量&流程控制(转载)

    文章目录 一 简介 1 1 scala语言的特点 1 2 第一个scala程序 二 变量 2 1 Scala变量的使用 2 2 Scala数据类型 2 3 值类型转换 三 循环控制 3 1 分支控制if else 3 2 for循环控制 S
  • opencv4应用开发基础

    opencv3 0版本以上都是用C 实现的 常用的一些函数及类型集中在cv命名空间里 cv Mat类型用于表示一个图像 构造函数除了空的构造函数外 还有很多个 Mat int rows int cols int type 创建指定行 列数的
  • springcloud常见面试题(2023最新)

    目录 前言 一 微服务 1 微服务是什么 2 你知道哪些RPC框架 3 springCloud和Dubbo有什么区别 4 SpringCloud由什么组成 二 Spring Cloud Eureka 1 Eureka包含几个组件 2 Eur
  • 探究Android SQLite3多线程

    http www cnblogs com xyczero p 4096297 html 最近做项目时在多线程读写数据库时抛出了异常 这自然是我对SQlite3有理解不到位的地方 所以事后仔细探究了一番 关于getWriteableDataB
  • visio增加连接点

    在画系统架构图的时候遇到一个问题 如果一个图形本来有的连接点不够 需要在任何的位置上增加连接点 看了很多网络介绍 但是总是增加不成功 继续发现接下来问题揭晓 2013版本visio举例 首先在开始中找到连接点 其次 按住ctrl键 在想要添
  • CBOW 与 skip-gram

    skip gram是利用中间词预测邻近词 cbow是利用上下文词预测中间词 一 CBOW 1 continues bag of words 其本质是通过context来预测word CBOW之所以叫连续词袋模型 是因为在每个窗口内它也不考虑
  • Sublime Text自定义配色方案

    先推荐介绍几款非常好用的自定义主题 https github com aziz tmTheme Editor http tmtheme editor herokuapp com 这个可以在线修改配色方案 也可以上传本地的方案修改 https
  • linux源码文件数量,Linux 下统计文件夹大小及文件数量

    查看文件夹大小 lib 目录大小 du sh lib lib 子目录大小 du sh lib 查看 lib 目录下普通文件大小 find lib type f xargs ls la awk F BEGIN sum 0 sum 5 END
  • prim算法解决最小生成树问题

    刚好这次又遇到了prim算法 就做了下整理 可以参考 数据结构与算法分析c 描述 这本书 个人而言 很经典 并把以前写的代码也整理了一下 做下分享 同时也加深下自己的理解 prim算法是解决最小生成树问题的一个很好的算法 此算法是是将点集合