最小生成树之Prim算法,浅显易懂

Prim算法主要思路:

抽象(假想:假设存在,但不存在)出两个集合,VVnew

  • 最开始,所以的图节点都在集合V中
  • 如果一个节点加入到了最小生成树中,则将该节点加入到Vnew(即Vnew保存的是最小生成树中的节点)

说明: Vnew即最小生成树

Prim算法主要维护三个数组

  • lowcost []int,表示V中的节点,离Vnew中所有节点的最短距离。如果节点已经加入到了Vnew中,则置为-1

  • latest []int,表示V中的节点,离Vnew中最近的节点的下标,如果节点已经加入到了Vnew中,则置为-1

  • v []int,表示V中节点的访问情况,最开始全部为0,表示未加入到Vnew中,若某节点加入到了V中, 则将其置为-1

步骤:

  1. 随机选择一个起点,并将其加入到Vnew中。同时,更新此时的lowcost、latest和v
  2. 遍历lowcost,寻找lowcost中的最小值min(假设为 j ),将与索引 j 相对应的节点加入到Vnew中,更新lowcost[j]、latest[j]和v[j]
  3. 找到最小值 j 后,此时lowcost和latest中的所有节点都要更新,因为此时Vnew节点增加了,V集合中的节点离Vnew集合的距离可能会缩短。
  4. 此时已更新完所有的lowcost和latest。
  5. 重复步骤2,直到访问了所有的节点

很明显,最后需要计算的最小生成树各节点之间的距离和 便是每一步中lowcost数组中的最小值min的和

证明:

不会

说明:Prim算法是基于顶点来进行查找的,所以与边的多少关系不大,比较适用与比较稠密的图。

golang 代码:

package main

import (
	"fmt"
	"math"
)

var MAXD = math.MaxInt64
//Prim
func Prim(e [][]int, start, n int) int {
	lowcost := make([]int, n) // 与Vnew最近的距离
	latest := make([]int, n)  // 距离Vnew中最近的点
	v := make([]int, n)       // 是否加入到Vnew
	sumD := 0

	for i := 1; i < n; i++ {
		lowcost[i] = e[start][i]
		if e[start][i] < MAXD {
			latest[i] = start
		}else {
			latest[i] = -1
		}
		v[i] = -1
	}

	for i := 1; i < n; i++ {
		var (
			min = MAXD
			k int
		)
		//找到离Vnew集合最近的外点
		for j := 0; j < n; j++ {
			if v[j] == -1 && lowcost[j] < min {
				min = lowcost[j]
				k = j
			}
		}
		//添加最短距离
		sumD += min

		//将k添加到Vnew
		v[k] = 0
		lowcost[k] = -1
		latest[k] = -1

		//更新lowcost
		for j := 0; j < n; j++ {
			if v[j] == -1 && e[k][j] < lowcost[j] {
				lowcost[j] = e[k][j]
				latest[j] = k
			}
		}
	}
	return sumD
}

//将edge转换成邻接矩阵的形式
func extract(edge [][]int, n int) [][]int {
	e := make([][]int, n)
	//初始化
	for i := 0; i < n; i++ {
		e[i] = make([]int, n)
		for j := 0; j < n; j++ {
			e[i][j] = MAXD
		}
	}
	//转化程邻接矩阵
	for i := 0; i < len(edge); i++ {
		e[edge[i][0]][edge[i][1]] = edge[i][2]
		e[edge[i][1]][edge[i][0]] = edge[i][2]
	}
	return e
}
func main() {
	//edge := [][]int{{0,1,4},{1,2,9},{1,3,3},{3,4,4}}
	edge := [][]int{{0,1,10000}}
	e := extract(edge,2)
	res := Prim(e,0,2)
	fmt.Println(res)
}




tips:

  1. 以点为基础,如何保存
    • 邻接矩阵即可
  2. V与Vnew如何隔离
    • 使用数组v来控制,-1属于v, 0属于Vnew
  3. 如何保存V中的点到Vnew集合的最短距离
    • 使用lowcost保存V中的点到Vnew的最短距离
  4. 距离保存好了,如何保存V中的点到Vnew中最近的点
    • 再新建一个数组latest,保存最近的点

每加入一个点到Vnew中之后,记得更新lowcostlatest两个数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值