什么是Prim算法?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是Prim算法?相关的知识,希望对你有一定的参考价值。

谢谢了

Prim算法
Prim算法用于求无向图的最小生成树

设图G =(V,E),其生成树的顶点集合为U。
①、把v0放入U。
②、在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树。
③、把②找到的边的v加入U集合。如果U集合已有n个元素,则结束,否则继续执行②。
其算法的时间复杂度为O(n^2)

Prim算法实现:
(1)集合:设置一个数组set[i](i=0,1,..,n-1),初始值为 0,代表对应顶点不在集合中(注意:顶点号与下标号差1)
(2)图用邻接阵表示,路径不通用无穷大表示,在计算机中可用一个大整数代替。

参考程序

/* Prim.c

Copyright (c) 2002, 2006 by ctu_85

All Rights Reserved.

*/

/* The impact of the situation of articulation point exists can be omitted in Prim algorithm but not in Kruskal algorithm */

#include "stdio.h"

#define maxver 10

#define maxright 100

int main()



int G[maxver][maxver],in[maxver]=,path[maxver][2];

int i,j,k,min=maxright;

int v1,v2,num,temp,status=0,start=0;

restart:

printf("Please enter the number of vertex(s) in the graph:\\n");

scanf("%d",&num);

if(num>maxver||num<0)



printf("Error!Please reinput!\\n");

goto restart;



for(j=0;j<num;j++)

for(k=0;k<num;k++)



if(j==k)

G[j][k]=maxright;

else

if(j<k)



re:

printf("Please input the right between vertex %d and vertex %d,if no edge exists please input -1:\\n",j+1,k+1);

scanf("%d",&temp);

if(temp>=maxright||temp<-1)



printf("Invalid input!\\n");

goto re;



if(temp==-1)

temp=maxright;

G[j][k]=G[k][j]=temp;





for(j=0;j<num;j++)



status=0;

for(k=0;k<num;k++)

if(G[j][k]<maxright)



status=1;

break;



if(status==0)

break;



do



printf("Please enter the vertex where Prim algorithm starts:");

scanf("%d",&start);

while(start<0||start>num);

in[start-1]=1;

for(i=0;i<num-1&&status;i++)



for(j=0;j<num;j++)

for(k=0;k<num;k++)

if(G[j][k]<min&&in[j]&&(!in[k]))



v1=j;

v2=k;

min=G[j][k];



if(!in[v2])



path[i][0]=v1;

path[i][1]=v2;

in[v1]=1;

in[v2]=1;

min=maxright;





if(!status)

printf("We cannot deal with it because the graph is not connected!\\n");

else



for(i=0;i<num-1;i++)

printf("Path %d:vertex %d to vertex %d\\n",i+1,path[i][0]+1,path[i][1]+1);



return 1;



Prim算法。

设图G =(V,E),其生成树的顶点集合为U。

①、把v0放入U。

②、在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树。

③、把②找到的边的v加入U集合。如果U集合已有n个元素,则结束,否则继续执行②。

其算法的时间复杂度为O(n^2)

参考程序

//Prim 算法 读入顶点数(n)、边数(m),边的起始点和权值 用邻接矩阵储存

//例如

//7 12 (7个顶点12条边)

//1 2 2

//1 4 1

//1 3 4

//2 4 3

//2 5 10

//3 4 2

//4 5 7

//3 6 5

//4 6 8

//4 7 4

//5 7 6

//6 7 1

#include <stdio.h>

#include <string.h>

int main()



int m , n;

int a[201][201] , mark[201] , pre[201] , dist[201];

int s , t , w;

int i , j , k , min , tot;

freopen("Prim.txt" , "r" , stdin);

//读入数据

memset(a , 0 , sizeof(a));

scanf("%d %d" , &n , &m);

for (i = 0; i < m; i ++)



scanf("%d %d %d" , &s , &t , &w);

a[s][t] = w; a[t][s] = w;



//赋初值

memset(mark , 0 , sizeof(mark));

memset(pre , 0 , sizeof(pre));

memset(dist , 9999 , sizeof(dist));

dist[1] = 0;

//Prim

for (i = 1; i <= n; i ++)



min = 9999; k = 0;

for (j = 1; j <= n; j ++)

if ((mark[j] == 0) && (dist[j] < min)) min = dist[j]; k = j;

if (k == 0) break;

mark[k] = 1;

for (j = 1; j <= n; j ++)

if ((mark[j] == 0) && (a[k][j] < dist[j]) && (a[k][j] > 0))



dist[j] = a[k][j];

pre[j] = k;





tot = 0;

for (i = 1; i <= n; i ++) tot += dist[i];

printf("%d\\n" , tot);

return 0;

参考技术A prim算法

最小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向完全图中选择n-1条边并使这个图仍然连通(也即得到了一棵生成树),同时还要考虑使树的权最小。
为了得到最小生成树,人们设计了很多算法,最著名的有prim算法和kruskal算法。教材中介绍了prim算法,但是讲得不够详细,理解起来比较困难,为了帮助大家更好的理解这一算法,本文对书中的内容作了进一步的细化,希望能对大家有所帮助。
假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树:
1:初始化:U=u 0,TE=�。此步骤设立一个只有结点u 0的结点集U和一个空的边集TE作为最小生成树的初始行态,在随后的算法执行中,这个行态会不断的发生变化,直到得到最小生成树为止。
2:在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0)。。。。。。。。。下面的内容请进入:

http://home.jznu.net/wu/sub1/post/24.html
参考技术B Prim算法。

设图G =(V,E),其生成树的顶点集合为U。

①、把v0放入U。

②、在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树。

③、把②找到的边的v加入U集合。如果U集合已有n个元素,则结束,否则继续执行②。

其算法的时间复杂度为O(n^2)

参考程序

//Prim 算法 读入顶点数(n)、边数(m),边的起始点和权值 用邻接矩阵储存

//例如

//7 12 (7个顶点12条边)

//1 2 2

//1 4 1

//1 3 4

//2 4 3

//2 5 10

//3 4 2

//4 5 7

//3 6 5

//4 6 8

//4 7 4

//5 7 6

//6 7 1

#include <stdio.h>

#include <string.h>

int main()



int m , n;

int a[201][201] , mark[201] , pre[201] , dist[201];

int s , t , w;

int i , j , k , min , tot;

freopen("Prim.txt" , "r" , stdin);

//读入数据

memset(a , 0 , sizeof(a));

scanf("%d %d" , &n , &m);

for (i = 0; i < m; i ++)



scanf("%d %d %d" , &s , &t , &w);

a[s][t] = w; a[t][s] = w;



//赋初值

memset(mark , 0 , sizeof(mark));

memset(pre , 0 , sizeof(pre));

memset(dist , 9999 , sizeof(dist));

dist[1] = 0;

//Prim

for (i = 1; i <= n; i ++)



min = 9999; k = 0;

for (j = 1; j <= n; j ++)

if ((mark[j] == 0) && (dist[j] < min)) min = dist[j]; k = j;

if (k == 0) break;

mark[k] = 1;

for (j = 1; j <= n; j ++)

if ((mark[j] == 0) && (a[k][j] < dist[j]) && (a[k][j] > 0))



dist[j] = a[k][j];

pre[j] = k;





tot = 0;

for (i = 1; i <= n; i ++) tot += dist[i];

printf("%d\n" , tot);

return 0;

参考技术C Prim算法用于求无向图的最小生成树

设图G =(V,E),其生成树的顶点集合为U。
①、把v0放入U。
②、在所有u∈U,v∈V-U的边(u,v)∈E中找一条最小权值的边,加入生成树。
③、把②找到的边的v加入U集合。如果U集合已有n个元素,则结束,否则继续执行②。
其算法的时间复杂度为O(n^2)

Prim算法实现:
(1)集合:设置一个数组set[i](i=0,1,..,n-1),初始值为 0,代表对应顶点不在集合中(注意:顶点号与下标号差1)
(2)图用邻接阵表示,路径不通用无穷大表示,在计算机中可用一个大整数代替。

参考程序

/* Prim.c

Copyright (c) 2002, 2006 by ctu_85

All Rights Reserved.

*/

/* The impact of the situation of articulation point exists can be omitted in Prim algorithm but not in Kruskal algorithm */

#include "stdio.h"

#define maxver 10

#define maxright 100

int main()



int G[maxver][maxver],in[maxver]=,path[maxver][2];

int i,j,k,min=maxright;

int v1,v2,num,temp,status=0,start=0;

restart:

printf("Please enter the number of vertex(s) in the graph:\n");

scanf("%d",&num);

if(num>maxver||num<0)



printf("Error!Please reinput!\n");

goto restart;



for(j=0;j<num;j++)

for(k=0;k<num;k++)



if(j==k)

G[j][k]=maxright;

else

if(j<k)



re:

printf("Please input the right between vertex %d and vertex %d,if no edge exists please input -1:\n",j+1,k+1);

scanf("%d",&temp);

if(temp>=maxright||temp<-1)



printf("Invalid input!\n");

goto re;



if(temp==-1)

temp=maxright;

G[j][k]=G[k][j]=temp;





for(j=0;j<num;j++)



status=0;

for(k=0;k<num;k++)

if(G[j][k]<maxright)



status=1;

break;



if(status==0)

break;



do



printf("Please enter the vertex where Prim algorithm starts:");

scanf("%d",&start);

while(start<0||start>num);

in[start-1]=1;

for(i=0;i<num-1&&status;i++)



for(j=0;j<num;j++)

for(k=0;k<num;k++)

if(G[j][k]<min&&in[j]&&(!in[k]))



v1=j;

v2=k;

min=G[j][k];



if(!in[v2])



path[i][0]=v1;

path[i][1]=v2;

in[v1]=1;

in[v2]=1;

min=maxright;





if(!status)

printf("We cannot deal with it because the graph is not connected!\n");

else



for(i=0;i<num-1;i++)

printf("Path %d:vertex %d to vertex %d\n",i+1,path[i][0]+1,path[i][1]+1);



return 1;

参考技术D 一楼的怎么那么不负责,你复制的内容地址是:http://jackie.blogcs.com/2006/12/prim.html
与Kr u s k a l算法类似,P r i m算法通过每次选择多条边来创建最小生成树。选择下一条边的贪婪准则是:从剩余的边中,选择一条耗费最小的边,并且它的加入应使所有入选的边仍是一棵树。最终,在所有步骤中选择的边形成一棵树。相反,在Kruskal 算法中所有入选的边集合最终形成一个森林。

P r i m算法从具有一个单一顶点的树T开始,这个顶点可以是原图中任意一个顶点。然后往T中加入一条代价最小的边( u , v)使Tè (u , v) 仍是一棵树,这种加边的步骤反复循环直到T中包含n- 1条边。注意对于边( u , v),u、v 中正好有一个顶点位于T中。P r i m算法的伪代码如图1 -1 4所示。在伪代码中也包含了所输入的图不是连通图的可能,在这种情况下没有生成树。图1 - 1 5显示了对图1-12a 使用P r i m算法的过程。把图1 - 1 4的伪代码细化为C + +程序及其正确性的证明留作练习(练习3 1)。

/ /假设网络中至少具有一个顶点
第5个回答  2006-12-21 小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向完全图中选择n-1条边并使这个图仍然连通(也即得到了一棵生成树),同时还要考虑使树的权最小。
为了得到最小生成树,人们设计了很多算法,最著名的有prim算法和kruskal算法。教材中介绍了prim算法,但是讲得不够详细,理解起来比较困难,为了帮助大家更好的理解这一算法,本文对书中的内容作了进一步的细化,希望能对大家有所帮助。
假设V是图中顶点的集合,E是图中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树:
1:初始化:U=u 0,TE=�。此步骤设立一个只有结点u 0的结点集U和一个空的边集TE作为最小生成树的初始行态,在随后的算法执行中,这个行态会不断的发生变化,直到得到最小生成树为止。
2:在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0),将此边加进集合TE中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合,这一点在理解算法时要密切注意。
3:如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。我们可以算出当U=V时,步骤2共执行了n-1次(设n为图中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。
了解了prim算法的基本思想以后,下面我们就可以看看具体的算法。
为了和教材保持一致,我们仍然规定:连通网用邻接矩阵net表示,若两个顶点之间不存在边,其权值为计算机内允许最大值,否则为对应边上的权值。
首先定义数据类型:
type adjmatrix=array [1..n,1..n] of real;
//定义一个n*n的矩阵类型adjmatrix,以便存储邻接矩阵//
edge=record
beg,en:1..n;
length:real;
end;
//定义边的存储结构为edge,其中beg是边的起点, en 是边的终点,length是边的权值//
treetype=array [1..n-1] of edge;
//定义一个基类型为edge的数组类型 treetype,其元素个数为n-1个//
var net:adjmatrix;
//定义一个adjmatrix类型的变量net,图的邻接矩阵就存放在net中//
tree:treetype;
//定义一个treetype类型的变量tree,tree中可以存放n-1条边的信息,包括起点、终点及权值。在算法结束后,最小生成树的n-1 条边就存放在tree中//
算法如下(设n为构造的出发点):
procedure prim(net:adjmatrix;var tree:treetype);
//过程首部.参数的含义是:值参数net传递图的邻接矩阵,变参tree指明最小生成树的存放地址//
begin
for v:=1 to n-1 do
//此循环将顶点n与图中其它n-1个顶点形成的n-1条边存放在变量tree中//
[tree[v].beg:=n;
tree[v].en:=v;
tree[v].length:=net[v]]
for k:=1 to n-1 do
//此循环执行算法思想中的步骤2,循环体每执行一次,TE中将增加一条边,在算法中,这条增加的边存放在变量tree中的第k个元素上,可以这样认为,tree中从第1到第k号元素中存放了TE和U的信息。注意:在算法思想中我们特别提醒了TE和U的动态性,表现在算法中,这种动态性 体现在循环变量k的变化上。//
[min:=tree[k].length;
for j:=k to n-1 do
if tree[j].length [min:=tree[j].length;
m:=j;]
//上面两条语句用于搜索权值最小的边//
v:=tree[m].en;
//此语句记录刚加入TE中的边的终点,也即即将加入U中的顶点//
edge:=tree[m];
tree[m]:=tree[k];
tree[k]:=edge;
//上面三句用于将刚找到的边存储到变量tree的第k号元素上//
for j:=k+1 to n-1 do
//此循环用于更新tree中第k+1到第n-1号元素。更新以后这些元素中的en子项是各不相同的,它们的全部就是集合V-U;beg子项则可以相同,但它们需满足两个条件:一是应属于集合U;另一是beg子项和en子项行成的边,在所有与顶点en联系的边中权值应最小。//
[d:=net[v.tree[j].en];
if d then [tree[j].length:=d;
tree[j].beg:=v;]
]
]
for j:=1 to n-1 do
//此循环用于输出最小生成树//
writeln(tree[j].beg,tree[j].en,tree[j].length);
end;
此算法的精妙之处在于对求权值最小的边这一问题的分解(也正是由于这种分解,而导致了算法理解上的困难)。按照常规的思路,这一问题应该这样解决:分别从集合V-U和U中取一顶点,从邻接矩阵中找到这两个顶点行成的边的权值,设V-U中有m个顶点,U中有n个顶点,则需要找到m*n个权值,在这m*n个权值中,再查找权最小的边。循环每执行一次,这一过程都应重复一次,相对来说计算量比较大。而本算法则利用了变量tree中第k+1到第n-1号元素来存放到上一循环为止的一些比较结果,如以第k+1号元素为例,其存放的是集合U中某一顶点到顶点tree.en的边,这条边是到该点的所有边中权值最小的边,所以,求权最小的边这一问题,通过比较第k+1号到第n-1号元素的权的大小就可以解决,每次循环只用比较n-k-2次即可,从而大大减小了计算量。

(原)最小生成树prim算法

//prim算法/C++
#include
using namespace std;

#define MAXVEX 10
#define MAX 65000
typedef char VexType;
typedef float AdjType;
struct GraphMatrix

VexType vexs[MAXVEX]; //顶点信息
AdjType arcs[MAXVEX][MAXVEX]; //边信息
int n; //图的顶点个数
;

struct Edge

int start_vex; //边的起点
int stop_vex; //边的终点
AdjType weight; //边的权
;

void edgeCopy(Edge *to,Edge *from)

to->start_vex=from->start_vex;
to->stop_vex=from->stop_vex;
to->weight=from->weight;


void prim(GraphMatrix *pgraph,Edge *mst)

int i,j;
int vx,vy;
int min;
AdjType weight,minweight;
Edge edge;

for(i=0;in-1;++i)

mst[i].start_vex=0;
mst[i].stop_vex=i+1;
mst[i].weight=pgraph->arcs[0][i+1];


for(i=0;in-1;++i)

minweight=MAX;
min=i;
for(j=i;jn-1;++j)
if(mst[j].weight
minweight=mst[j].weight;
min=j;

edgeCopy(&edge,&mst[min]);
edgeCopy(&mst[min],&mst[i]);
edgeCopy(&mst[i],&edge);
vx=mst[i].stop_vex;
for(j=i+1;jn-1;++j)

vy=mst[j].stop_vex;
weight=pgraph->arcs[vx][vy];
if(weight

mst[j].weight=weight;
mst[j].start_vex=vx;



以上是关于什么是Prim算法?的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树的prim算法 边的权值为啥不能为负值

最小生成树的prim算法 边的权值为啥不能为负值

prim和kruscal算法得到的最小生成树是不是一样

Prim算法详解

为什么Prim算法不适用于带权有向图

随便搞搞 1 prim算法的学习和使用