最小生成树——Prim算法



查看原文:http://www.wyblog.cn/2016/12/14/%e6%9c%80%e5%b0%8f%e7%94%9f%e6%88%90%e6%a0%91-prim%e7%ae%97%e6%b3%95/

一个无向图的最小生成树就是由该图的那些连接G的所有顶点的边构成的树,且其所有边权值之和最低。从定义可见,它是包含了图的所有顶点的最小树。 求解最小生成树经典算法即为Prim算法。 Prim算法是使得这个树一步步生长而成,因为最小生成树必定包含了所有顶点,所以可以任意选择起点。在生成树过程中的每一步,都要把一个节点当做根并往上加边。 Prim算法跟Dijkstra算法神似,它也是每一步中都去扫描还被标记为未知的那些顶点,然后找出dist最低的边,它一定是属于最小生成树的边,所以把这个顶点再标记为已知,再去更新跟这个顶点相临近的那些顶点的dist值。 在了解Prim算法之前,可以看看Dijkstra算法:

http://www.wyblog.cn/2016/12/09/%E5%B8%A6%E6%9D%83%E8%B7%AF%E5%BE%84%E6%9C%80%E7%9F%AD-dijkstra%E7%AE%97%E6%B3%95/

Prim算法的程序总体上跟Dijkstra算法是一样的,有少许区别。

  1. 最小生成树一般是对应的无向图,所以在构造图的时候,会把每条边认为是双向的,所以每条边要在图的邻接链表里添加两次。见代码里的CreateDAG函数。
  2. 顶点结构体里的dist所存的内容不同,在Dijkstra算法里,存的是最小路径之和,而在Prim算法里,存的是最小的权值。所以,在更新dist的代码差生了变化,变为了 $latex d_{\omega} = min ( d_{\omega},c_{\omega,v}) $。
  3. 打印最小生成树时,直接遍历所有顶点,并打印出对应的path值就可以了。

代码如下:


#include<cstdio> #include<iostream> #include<queue> #include<algorithm> using namespace std; #define MAX_VERTEX_NUM 100 #define Vertextype int #define Infinity 0xffff #define NotAVertex -1 typedef struct EdgeNode { int adjVertex; int weight; //邻接权重 EdgeNode *nextEdgeNode; }EdgeNode; typedef struct VerNode { int Known; Vertextype data; int dist; int path; EdgeNode *firstedge; }VerNode; typedef struct Graph { VerNode verNode[MAX_VERTEX_NUM]; int vertex_num,edge_num; }Graph; void CreateDAG(Graph &G,int n,int e) { int i,j,w,k; G.vertex_num=n; G.edge_num=e; for(i=1;i<=n;i++) { cin>>G.verNode[i].data; G.verNode[i].Known=0; G.verNode[i].dist=Infinity; G.verNode[i].path=-1; G.verNode[i].firstedge=NULL; } for(k=1;k<=e;k++) //无向图,所以邻接表要生成两份 { EdgeNode *p; cin>>i>>j>>w; p=new EdgeNode; p->adjVertex=j; p->weight=w; p->nextEdgeNode=G.verNode[i].firstedge; G.verNode[i].firstedge=p; p=new EdgeNode; p->adjVertex=i; p->weight=w; p->nextEdgeNode=G.verNode[j].firstedge; G.verNode[j].firstedge=p; } } void Prim(Graph &G,int n,int start) //求最小生成树Prim算法 { VerNode V; EdgeNode *w; int i,j,temp_num,temp_dist; G.verNode[start].dist=0; G.verNode[start].path=0; for(i=1;i<=n;++i) //n个点待查找 { temp_dist=Infinity; temp_num=0; for(j=1;j<=n;++j) //先寻找未知的最短顶点 { if(G.verNode[j].Known==0 && G.verNode[j].dist<temp_dist) { temp_dist=G.verNode[j].dist; temp_num=j; } } G.verNode[temp_num].Known=1; w=G.verNode[temp_num].firstedge; while(w) { if(G.verNode[w->adjVertex].Known==0) { G.verNode[w->adjVertex].dist = min(G.verNode[w->adjVertex].dist,w->weight); if(G.verNode[w->adjVertex].dist == w->weight) //说明权值被更新,那么就要更新路径标记 G.verNode[w->adjVertex].path=G.verNode[temp_num].data; } w=w->nextEdgeNode; } } } int PrintMST(Graph &G,int n) //打印最小生成树 { for(int i=1;i<=n;i++) printf("%d <=> %d\n",i,G.verNode[i].path); } int main() { Graph G; CreateDAG(G,7,12); //给出图的顶点数及边数量 Prim(G,7,1); //给出顶点数以及起点编号 PrintMST(G,7); //给出顶点数,打印最小生成树 } /******************** 1 2 3 4 5 6 7 1 2 2 1 4 1 2 4 3 2 5 10 3 1 4 3 6 5 4 3 2 4 5 7 4 6 8 4 7 4 5 7 6 7 6 1 输出: 1 <=> 0 2 <=> 1 3 <=> 4 4 <=> 1 5 <=> 7 6 <=> 7 7 <=> 4 *********************/


查看原文:http://www.wyblog.cn/2016/12/14/%e6%9c%80%e5%b0%8f%e7%94%9f%e6%88%90%e6%a0%91-prim%e7%ae%97%e6%b3%95/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值