01最小生成树——Prim算法

01基于Prim算法的最小生成树

1. 问题

给定一无向连通图G = (V, E) ,其中V为G的顶点集,E为G的边集,(u, v) 代表连接顶点 u 与顶点 v 的边,w(u, v) 代表此边的权重。
若存在树 T ,其顶点集V’与G的顶点集V一一对应、边集E’为G边集E 的子集,且T无循环,使得 w(T) 最小,则称 T 为 G 的最小生成树(spanning tree)。
数学表达式

如何快速、准确地找到最小生成出树呢?

2. 解析

本文主要描述基于Prim算法的最小生成树构造过程。

Prim算法的核心思想为:

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:V’ = {x},其中x为集合V中的任一节点(起始点),E’ = {},为空;

3).重复下列操作,直到V’ = V: a.在集合E中选取权值最小的边<u, v>,其中u为集合V’中的元素,而v不在V’集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一); b.将v加入集合V’中,将<u, v>边加入集合E’中;

4).输出:使用集合V’和E’来描述所得到的最小生成树。
(参考百度百科-Prim算法)

举个栗子:

给定一有6顶点的无向图连通图G = (V, E) ,顶点和边的对应关系及各边权重如下图所示:
图
这里首先选取 顶点C 加入最小生成树 T 的顶点集 V’ 。
P1
其次,以已加入V’的顶点为起点,以未加入V’且在V里的顶点为终点,在边集E中选择权重最小的边,加入到E’,并判断当前的T是否构成环。
p2
若不构成环,将终点顶点和该边分别加入到V’和E’;若构成环,不断比较出次小的边直至不成环,并将对应的终点顶点和该边分别加入到V’和E’。(图中绿线表示同一阶段进行比较的边,红线表示已加入V’或E’的点或边,蓝线表示被初步选择的边成环,该边将被舍弃。)
重复上述步骤,当V’=V时,所呈现的边集和点集即构成给定图的最小生成树。(基于此,后面步骤不再详述。)
p3
P4
P5
P6
P7
P8
P9
P10
P11
按步骤,该阶段被选择的应该是权值为9的边,但此边的加入使得T构成了环,因此被舍弃,下同。
P12
P13
至此,G中所有顶点都已加入T中,最小生成树构造完毕,其权值为40.

3.设计

int Prim(SGraph g, int s) {

	for ( i from 0 to MAXSIZE-1 )
		//n为顶点数,初始化每个点的最小边权值为某一极大值(如65535)
		
	//将传入的顶点s作为第一个初始顶点
	node[s].data = s;
	//顶点s的lowestvalue置0,表示顶点s入生成树
	node[s].lowestvalue = 0;
	
	//输入点s到其他点的边权值
	for ( i from 0 to MAXSIZE-1 ) {
		if (i != s) {
			node[i].lowestvalue = g.A[s * MAXSIZE + i];
			node[i].data = s;
		}
	}
	
	//每一次往生成树加一条边,直至共加入MAXSIZE-1条边
	for ( j from 1 to MAXSIZE-1 ) {

		//找到最小权值边且终点顶点未被加入的顶点,记下k;
		int k = Getmin(node);
		
		//累加权值
		sumValue += node[k].lowestvalue;
		//顶点k的lowestvalue置0,表示顶点k入生成树
		node[k].lowestvalue = 0;

		//更新以未加入顶点为终点的较小边权值
		for (int m = 0; m < MAXSIZE; m++) {
			if (node[m].lowestvalue > g.A[k * MAXSIZE + m]) {
				node[m].lowestvalue = g.A[k * MAXSIZE + m];
				node[m].data = k;
			}
		}
	}
	//返回最小生成树总权值
}

4.源码

https://github.com/KabgRs/F-SDDR/tree/%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90%E4%B8%8E%E8%AE%BE%E8%AE%A1%E4%BD%9C%E4%B8%9A/01%E6%9C%80%E5%B0%8F%E7%94%9F%E6%88%90%E6%A0%91_Prim%E7%AE%97%E6%B3%95

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值