剖析prim最小生成树算法

在上一篇博客中,已经用代码实现了这个算法。只是我认为从算法到代码实现,这是一个很大的过渡,不喜欢教科书式的顺理成章的过渡,虽然下面写的不知所云,虽然我很菜。

看完上篇博客中代码,想想其中一些问题,

1、如何将图的相互关系,用合适的数据结构来表示

2、如何搜索某一节点周围的权值路径

3、如何将新的节点加入到新的搜索库中。

第一个问题

对于这个图关系,用什么样的数据结构来表示,这里有两两之间的关系,能想到的树、队列、等等,好像都不能,

找到了一篇博客

http://blog.csdn.net/zscacm/article/details/7209098

研究图的表示方法的。本质上就是相互之间的关系太复杂,没有固定的前驱和后继。常用的数组能将这种关系表示出来,

第二个问题

按照prim算法的第一步,

选择一个点作为入口(假设为A),将A加入备选结合,找出与这个集合相连的节点,并找出其中最小的权值,

如何将这种思想程序化,已经建立图的二维数组存储方式,从数组中可以看出,与A相连的节点是B和C,就是数组中第一行所体现的关系。

这里好多问题,有点乱,为什么要找这种关系,这种关系的本质是什么。prim的核心思想是什么。

所以抛开前面 重新看看prim算法的过程

有一种算法过程步骤:

1.将第一个点放入最小生成树的集合中(标记visit[i]=1意思就是最小生成树集合)。

2.初始化lowcost[i]为跟1点相连(仅仅相连)的边的权值(lowcost[i]不是这个点的最小权值!在以后会逐步更新)。

3.枚举n个顶点

4.将找出来的最小权值的边的顶点加入最小生成树的集合中(标记visit[i]= 1),权值想加。

5.更新lowcost[j]集合。

关键步骤:实质就是每在最小生成树集合中加入一个点就需要把这个点与集合外的点比较,不断的寻找两个集合之间最小的边

6.循环上述步骤,指导将全部顶点加入到最小生成树集合为止。

看了上面这个图,想想这个过程是一个循环过程,那么循环的主体是什么,

每一次循环都是在将一个点加入某个集合,而决定加入这个点的原因就是在所有的点中,它到集合的权重是最小的。

一直循环,将权重最小的点加入到这个集合,直到所有点都已被加入。

如何表示集合的概念?什么是集合?集合就是具有某些属性一直的对象在一起。最简单的就是用变量标记,比如每个对象都包含一个成员变量,这个成员变量用于说明此对象的属性。而在此处,可以用一个数组来体现这个集合,数组下标表示是哪个对象,而对应数组元素则表示是否属于集合元素

如何获取集合与节点之间的关系权重?如果出现下面这种情况

也就是说集合与某一节点有不止一个权重路径,prim算法是需要更新结合与节点的权值路径,保证是最短的,然后再去寻找下一个加入结合的节点。

如何更新或者说当一个新的结点加入集合后,如何找出新的与结合相连的节点。

比如

当前集合包含节点1,与其相连的节点为2、3、4

找到下一个节点是,3

然后新的集合产生,而与新的集合相连的节点少了3、多了5.

而多出来的节点,实际是由新加入的节点3带来的。所以要扩充更新这个连接节点库,就是看看节点3的节点库。

所以总结一下prim的过程就是

1)将第一个节点加入集合,更新这个集合的外节点库,

2)从外节点库中找出权重最小的节点,加入集合,更新这个集合的外节点库

3)循环2,直到所有节点都加入到集合中。

下面是重新整理的一段代码,分别对应上面的步骤

vector < int > que;

用于存放集合外节点库,

vector < int > flag;

用于标记集合内的节点

第一步:

将第一个节点加入集合,更新这个集合的外节点库,

loc=0;

flag[loc]=1; //将位置0的节点加入集合

for(i=0;i

int stree(int map[N][N],int num)
{
 int i=0;
 int j=0;
 int min;
 int loc;
 int minsum=0;
 vector < int > que;
 vector < int > flag;
 que.resize(num);
 flag.resize(num);
 for(i=0;i<num;++i)
  que[i]=MAX;

 loc=0;
 flag[loc]=1;
 for(i=0;i<num;++i)
 {
  if(i!=loc)
   que[i]=map[loc][i];
 }

 for(i=0;i<num-1;++i)
 {
  min=MAX;
  for(j=0;j<num;++j)
  {
   if(min>que[j] && flag[j]!=1)
   {
    min=que[j];
    loc=j;
   }
  }
  minsum+=min;

  flag[loc]=1;

  for(j=0;j<num;++j)
  {
   if(flag[j]!=1 && map[loc][j]<que[j])
    que[j]=map[loc][j];
  }

 }
 return minsum;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 13:05:13

剖析prim最小生成树算法的相关文章

Prim 最小生成树算法

Prim 算法是一种解决最小生成树问题(Minimum Spanning Tree)的算法.和 Kruskal 算法类似,Prim 算法的设计也是基于贪心算法(Greedy algorithm). Prim 算法的思想很简单,一棵生成树必须连接所有的顶点,而要保持最小权重则每次选择邻接的边时要选择较小权重的边.Prim 算法看起来非常类似于单源最短路径 Dijkstra 算法,从源点出发,寻找当前的最短路径,每次比较当前可达邻接顶点中最小的一个边加入到生成树中. 例如,下面这张连通的无向图 G,

prim最小生成树算法题poj2485

开始想用kruskal算法自己写写runtime error #include<cstdio> #include<queue> #include<set> using namespace std; int a[2510][25100]; struct weight { int a,b; int value; bool operator < (const weight & rhs) const { return value < rhs.value; }

HDU1863 - 畅通工程 Prim最小生成树算法

HDU1863 - 畅通工程:http://acm.hdu.edu.cn/showproblem.php?pid=1863 这题我中午用并查集的方法AC了一次,下午学了Prim.换个姿势,再来一次 = =! 并查集的方法:http://blog.csdn.net/p_rogrammer/article/details/47979073 代码: #include <iostream> #include <cstdio> #include <vector> #include

最小生成树(MST)----普里姆(Prim)算法与克鲁斯卡尔(Kruskal)算法

1.概念:给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树. 2.应用:例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低.这就需要找到带权的最小生成树. 3.求最小生成树的算法 3.1 普里姆(Prim)算法 方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树

c/c++ 用普利姆(prim)算法构造最小生成树

c/c++ 用普利姆(prim)算法构造最小生成树 最小生成树(Minimum Cost Spanning Tree)的概念: ? 假设要在n个城市之间建立公路,则连通n个城市只需要n-1条线路.这时,自然会考虑,如何在最节省经费的前提下建立这个公路网络. ? 每2个城市之间都可以设置一条公路,相应地都要付出一定的经济代价.n个城市之间,最多可以设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,以使总的耗费最少? 普利姆(prim)算法的大致思路: ? 大致思想是:设图G顶点

笔试算法题(50):简介 - 广度优先 &amp; 深度优先 &amp; 最小生成树算法

广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能非递归实现: 相比DFS较快,空间换时间: 适合广度大的图: 空间复杂度:邻接矩阵O(N^2):邻接表O(N+E): 时间复杂度:O(V+E): DFS优缺点: 无论是系统栈还是用户栈保存的节点数都只是树的深度,所以空间耗用小: 有递归和非递归实现: 由于有大量栈操作(特别是递归实现时候的系统调用),执行速度

hdu 1162 Eddy&#39;s picture(最小生成树算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1162 Eddy's picture Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6866    Accepted Submission(s): 3469 Problem Description Eddy begins to like p

最小生成树算法汇总 (普里姆 &amp;&amp; 克鲁斯卡尔与并查集结合)

最小生成树: 今天研究了一下最小生成树,感觉最小生成树算法与最短路算法 相差不大,从Prim 与 Dijskrs算法可以看出 最小生成树即最小权重生成树,主要适用于 N个点之间 构造N-1线路,使N个点之间任意两点之间都可到达, 但是N个点之间 不构成回路,并且这N-1条线路的权重之和最小即 消耗最小. 注意:在构造最小生成树,加入新的节点时,不仅要保证权重最小,首要条件是 不能构成回路. 以图示为例,构造最小生成树 (一)普里姆   以下步骤 (二) 克鲁斯卡尔 最终的最小生成树 和 普里姆一

数据结构基础温故-5.图(中):最小生成树算法

图的“多对多”特性使得图在结构设计和算法实现上较为困难,这时就需要根据具体应用将图转换为不同的树来简化问题的求解. 一.生成树与最小生成树 1.1 生成树 对于一个无向图,含有连通图全部顶点的一个极小连通子图成为生成树(Spanning Tree).其本质就是从连通图任一顶点出发进行遍历操作所经过的边,再加上所有顶点构成的子图. 采用深度优先遍历获得的生成树称为深度优先生成树(DFS生成树),采用广度优先遍历获得的生成树称为广度优先生成树(BFS生成树).如下图所示,无向图的DFS生成树和BFS