最小生成树——Prim算法

来源:互联网 发布:淘宝会查物流重量吗 编辑:程序博客网 时间:2024/05/20 06:09


查看原文: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 -1typedef 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 71 2 21 4 12 4 32 5 103 1 43 6 54 3 24 5 74 6 84 7 45 7 67 6 1输出:1 <=> 02 <=> 13 <=> 44 <=> 15 <=> 76 <=> 77 <=> 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 0