Prim算法

假设无向图中有n个顶点,那我们总共需循环n-1次,找到n-1条变加入到最小生成树当中
开始任意选择一个结点加入到最小生成树中,并将非生成树中的所有顶点与生成树中的顶点的距离设置为Max最大值(因为此时这些结点还没有加入到最小生成树中,因此两树之间的距离是无穷大的)

接下来就是Prim算法的核心步骤:
1.找非生成树距离最小生成树的最近节点
2.将这个节点加入到最小生成树当中
3.更新所有非生成树节点到最小生成树的距离(随着新节点的加入,非生成树节点到最小生成树节点的距离会更新,将这个距离更新成距离最小生成树的最近距离,因为非最小生成树节点与生成树中的多个节点可能都有连接,因此这个节点到最小生成树的距离可能不止一个,我们将这个距离更新成最小的那个)

接下来对上面三个步骤进行重复,我们用一个数组来存放非生成树到最小生成树的距离,用一个数组来存放最小生成树中的边权,并给已经放入最小生成树的节点赋值做上标记,由于第二步中有新节点的加入,并且我们在第三步时更新了非生成树到最小生成树的距离,所以我们又能执行第一步,在第三步更新的数组中把最小距离的节点再次加入到最小生成树中,然后继续更新,继续查数组,继续加入到生成树中

最后我们得到n-1最小权值和的边,称为最小生成树,最小生成树的应用之一是:我们需要在n个城市之间铺路,求怎样铺路可以将所有城市连接起来的同时铺路费最小。这时毫无疑问,我们肯定只会铺n-1条路,因为n-1条路就能将n个城市连接起来了。Prim算法的核心在于通过求最小生成树求出最小铺路费

以下是Prim算法的C语言实现:
#include
using namespace std;
#define MAXV 100 //最大顶点个数,可根据需要修改
#define INF INT_MAX //用无穷大表示无边

typedef int InfoType; //顶点其他信息类型,这里简化为int

typedef struct
{
int no; //顶点编号
InfoType info; //顶点其他信息
} VertexType;

//图的邻接矩阵存储类型定义
typedef struct
{
int edges[MAXV][MAXV]; //邻接矩阵
int n, e; //顶点数,边数
VertexType vexs[MAXV];//存放顶点信息
}MatGraph;

void Prim(MatGraph g, int v) { //v是最小生成树的起始节点
int lowcost[MAXV];//记录V-U集合中顶点到U集合的最小边权值
int closest[MAXV];//记录最小边在U集合的邻接顶点
int i, j, k, min;

for (int i = 1; i < g.n; i++) {
lowcost[i] = g.edges[v][i]; //初始为起点v到各顶点的边权值
closest[i] = v; //初始邻接顶点都为v
}
lowcost[v] = 0; //起始顶点加入U集合,权值设为0

//Prim三部曲,第一步:选距离生成树最近节点 共需选取n-1条边,循环n-1次
for (int i = 1; i < g.n; i++) { //找出n-1个顶点
min = INF;
k = 0;
//找到当前V-U中权值最小的边对应的顶点k
for (j = 0; j < g.n; j++) {
if (lowcost[j] != 0 && lowcost[j] < min) { //lowcost[j]表示顶点j与起始顶点的最小权值
//选取最小生成树节点的条件:
//(1)不在最小生成树中
//(2)距离最小生成树最近的节点
min = lowcost[j];
k = j; //k记录最近顶点的编号
}
}

//输出当前选中的边:closest[k] ->k
printf("边(%d,%d)权值:%d\n", closest[k],k, min);

//Prim三部曲第二步:将距离最近的顶点加入到最小生成树U中
lowcost[k] = 0;//将顶点k加入到U集合

//更新lowcost和closest,因为k加入后,可能产生更小的边
//Prim三部曲第三步:更新非生成树节点到最小生成树的距离
for (j = 0; j < g.n; j++) {
if (lowcost[j] != 0 && g.edges[k][j] < lowcost[j]) {
lowcost[j] = g. edges[k][j]; //更新非生成树到最小生成树的距离
closest[j] = k;
}
}
}
}

}

posted @ 2026-03-16 21:42  ZealousMclaren  阅读(9)  评论(0)    收藏  举报