普里姆(Prim)算法
1、Prim算法思想
Prim算法的基本思想是以顶点为主导地位:从起始顶点出发,通过选择当前可用的最小权值边依次把其他顶点加入到生成树当中来。
设连通无向网为G(V,E),在普里姆算法中,将顶点集合V分成两个子集合T和T1。
(1)T:当前生成树顶点集合;
(2)T1:不属于当前生成树的顶点集合。
很显然,T∪T1 = V。Prim的具体过程如下:
(1)从连通无向网G中选择一个起始顶点u0,首先将它加入到集合T中;然后选择与u0关联的、具有最小权值的边(u0, v),将顶点v加入到顶点集合T中;
(2)以后每一步选出在T中的一个顶点u,另一个在T1中的顶点v所组成的各条边中权值最小的边(u, v),将v加入集合T中。按此步骤,直至网络中的所有顶点都加入到生成
树顶点集合T中为止~
2、Prim算法实现
下面用一个具体的例子来实现Prim算法~如下图:
例、利用Prim算法求上图所示的无向网的最小生成树,并输出依次选择的各条边及最终求得的最小生成树的权。
先输入顶点个数和边数,然后输入每条边的数据。顶点序号从1开始。
Code:
#include<stdio.h> #include<string.h> #define INF 1000000 //无穷大 #define MAXN 21 //顶点个数最大值 int n, m; //顶点个数、边数 int Edge[MAXN][MAXN]; //邻接矩阵 int lowcost[MAXN]; //记录集合T1中各顶点到集合T内各顶点权值最小的边的权值 int nearvex[MAXN]; //记录集合T1中各顶点距离顶点集合T内哪个顶点最近;当nearvex[i] = -1时,表示顶点i属于集合T void prim(int u0) //从顶点u0出发执行prim算法 { int i, j; //循环变量 int sumweight = 0; //生成树的权值 for(i = 1; i <= n; i++) //初始化lowcost数组和nearvex数组 { lowcost[i] = Edge[u0][i]; nearvex[i] = u0; } nearvex[u0] = -1; for(i = 1; i < n; i++) { int min = INF; int v = -1; //在lowcost数组中找最小值 for(j = 1; j <=n; j++) if(nearvex[j]!=-1 && lowcost[j]<min) { v = j; min = lowcost[v]; } if(v != -1) //表示找到权值最小的边 { printf("%d %d %d\n", nearvex[v], v, lowcost[v]); nearvex[v] = -1; //将选出的边的状态置为-1,表示在集合T中 sumweight += lowcost[v]; //由于集合T新加入了顶点v,所以要更新lowcost中顶点v与T1集合中各顶点的距离,同时将更新的顶点记录到nextvex中 for(j = 1; j <= n; j++) if(nearvex[j]!=-1 && Edge[v][j]<lowcost[j]) { lowcost[j] = Edge[v][j]; nearvex[j] = v; } } } printf("The weight of MST is %d\n", sumweight); } int main() { int i, j; int u, v, w; scanf("%d%d", &n, &m); memset(Edge, 0, sizeof(Edge)); //构造邻接矩阵 for(i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &w); Edge[u][v] = Edge[v][u] = w; } for(i = 1; i <= n; i++) for(j = 1; j <=n; j++) { if(i == j) Edge[i][j] = 0; else if(Edge[i][j] == 0) Edge[i][j] = INF; } printf("The lines chosen are :\n"); prim(1); //从顶点1出发构造最小生成树 return 0; }运行结果:
原文:http://blog.csdn.net/zenail501129/article/details/23735113