Prim算法(普里姆算法)

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。

算法描述

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:V new = {x},其中x为集合V中的任一节点(起始点),E new = {},为空;
3).重复下列操作,直到V new = V:
a.在集合E中选取权值最小的边,其中u为集合V new中的元素,而v不在V new 集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合V new中,将边加入集合E new中;
4).输出:使用集合V new和E new来描述所得到的 最小生成树。

 时间复杂度   
Prim算法的时间复杂度             邻接表存储时,是 O(n+e)
                                                  邻接矩阵的时候 是O(n^2 )

最小边、权的数据结构 时间复杂度(总计)
邻接矩阵、搜索 O(V^2)
二叉堆(后文伪代码中使用的数据结构)、邻接表 O((V + E) log(V)) = O(E log(V))
斐波那契堆、邻接表 O(E + V log(V))
通过邻接矩阵图表示的简易实现中,找到所有最小权边共需O(V)的运行时间。使用简单的二叉堆与邻接表来表示的话,普里姆算法的运行时间则可缩减为O(ElogV),其中E为连通图的边数,V为顶点数。如果使用较为复杂的斐波那契堆,则可将运行时间进一步缩短为O(E+VlogV),这在连通图足够密集时(当E满足Ω(VlogV)条件时),可较显著地提高运行速度。

图例描述

图例 说明 不可选 可选 已选(Vnew
Prim算法(普里姆算法)_第1张图片
此为原始的加权连通图。每条边一侧的数字代表其权值。 - - -
Prim算法(普里姆算法)_第2张图片
顶点D被任意选为起始点。顶点ABEF通过单条边与D相连。A是距离D最近的顶点,因此将A及对应边AD以高亮表示。 C, G A, B, E, F D
Prim算法(普里姆算法)_第3张图片
下一个顶点为距离DA最近的顶点。BD为9,距A为7,E为15,F为6。因此,FDA最近,因此将顶点F与相应边DF以高亮表示。 C, G B, E, F A, D
Prim算法(普里姆算法)_第4张图片
算法继续重复上面的步骤。距离A为7的顶点B被高亮表示。 C B, E, G A, D, F
Prim算法(普里姆算法)_第5张图片
在当前情况下,可以在 CEG间进行选择。 CB为8, EB为7, GF为11。点 E最近,因此将顶点 E与相应边 BE高亮表示。
C, E, G A, D, F, B
Prim算法(普里姆算法)_第6张图片
这里,可供选择的顶点只有CGCE为5,GE为9,故选取C,并与边EC一同高亮表示。 C, G A, D, F, B, E
Prim算法(普里姆算法)_第7张图片
顶点G是唯一剩下的顶点,它距F为11,距E为9,E最近,故高亮表示G及相应边EG G A, D, F, B, E, C
Prim算法(普里姆算法)_第8张图片
现在,所有顶点均已被选取,图中绿色部分即为连通图的最小生成树。在此例中,最小生成树的权值之和为39。 A, D, F, B, E, C, G

c代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include
#include
#definemax1000000000;
inta[1001][1001],d[1001],p[1001];
intmain(){
inti,j,k,m,n,min,ans,t;
intx,y,z;
scanf ( "%d%d" ,&n,&m);
for (i=1;i<=m;i++){
scanf ( "%d%d%d" ,&x,&y,&z);
a[x][y]=z;
a[y][x]=z;
}
for (i=1;i<=n;i++)
d[i]=1000000000;
d[1]=0;
for (i=2;i<=n;i++){
min=max;
for (j=1;j<=n;j++)
if (!p[j]&&min>d[j])
min=d[j];
t=j;
}
p[t]=j;
for (j=1;j<=n;j++)
if (a[t][j]=0&&d[j]>a[t][j]){
d[j]=a[t][j];
ans+=min;
}
printf ( "%d" ,ans);
return0;
}

C++代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#defineMAXN1000
#defineINF1<<30
intclosest[MAXN],lowcost[MAXN],m;//m为节点的个数
intG[MAXN][MAXN];//邻接矩阵
intprim()
{
for(inti=0;i
{
lowcost[i]=INF;
}
for(inti=0;i
{
closest[i]=0;
}
closest[0]=-1;//加入第一个点,-1表示该点在集合U中,否则在集合V中
intnum=0,ans=0,e=0;//e为最新加入集合的点
while(num
{
intmicost=INF,miedge=-1;
for(inti=0;i
if(closest[i]!=-1)
{
inttemp=G[e][i];
if(temp
{
lowcost[i]=temp;
closest[i]=e;
}
if(lowcost[i]
micost=lowcost[miedge=i];
}
ans+=micost;
closest[e=miedge]=-1;
num++;
}
returnans;
}



你可能感兴趣的:(c/c++,读书笔记)