定义
在一个无向有权图中,能遍历完所有的节点并且花费的代价最小,这样就构成了一颗最小生成树
prim算法
简介:通过贪心算法,整个图中只存在一颗最小生成树,每次遍历的时候,将树外面的代价最小的一个节点添加进来
借鉴了景明先生的图:它的描述更详细些链接:图解:什么是最小生成树
伪代码(待完善)
for v := range G{
v.Father = None
v.Val = 无穷大
}
root = v
root.Val = 0 // 设置权重最小,选他来做为第一个节点
Queue = MinFirstQueue(G) //最小优先队列, 里面存放的值是当前“prim树”能够到达该节点的代价
for ;;{
if(Queue.IsEmpty()){
break
}
u = Queue.Pop() // 弹出val最小的节点,所以第一个被弹出的肯定是root
for v:=u.neighbor(){
if v 属于 Queue and W(u, v) < v.Val{// 节点v没有在prim树中,并且节点u到v的权重小于v到father节点的权重
// 发现更优路径,替换v的父节点
v.Father = u
v.val = w(u, v)
Queue.Update() //替换了最小值,也要更新最小队列
}
}
}
这样,从root节点开始往下走,就能找到一颗prim树了
go语言代码:统计最小生成树的和
最好以后再来完善,使用对象生成一颗真正的生成树
package main
import "fmt"
// 图:
// 解释:(0, 1) 位置上的3 表示从v0到v3的权重为3
var lstGrap [9][9]int
// 0, 3, 0, 0, 0, 4, 0, 0, 0
// 3, 0, 8, 0, 0, 0, 6, 0, 5
// 0, 8, 0, 12,0, 0, 0, 0, 0
// 0, 0, 12,0, 10,0, 14,6, 0
// 0, 0, 0, 10,0, 18,0, 1, 0
// 4, 0, 0, 0, 18,0, 7, 0, 0
// 0, 6, 0, 14,0, 7, 0, 9, 0
// 0, 0, 0, 6, 1, 0, 9, 0, 0
// 0, 5, 2, 11,0, 0, 0, 0, 0
// 要求:统计最小生成树的和
func Prim() int {
lstTree := make([]int, 9) //已经加入最小生成树的节点
fmt.Printf("lstTree容量:%v, len: %v\n", len(lstTree), cap(lstTree))
iNode := 0
iSum := 0
lstTree = append(lstTree, iNode) //选定v0作为root节点,开始生成最小生成树
for { //循环直到遍历完所有节点
if len(lstTree) == 9 { //做个保底,这里应该是不会被执行到的
print("break")
break
}
lstNextNodeInfo := FindMinNeibor(lstTree)
iNextNode := lstNextNodeInfo[0]
iWeight := lstNextNodeInfo[1]
if iNextNode == -1 { // 没找到下一个节点就代表遍历结束,直接返回
return iSum
} else {
fmt.Printf("选择路径:V%v --> V%v 权重:%v\n", iNode, iNextNode, iWeight)
iSum += iWeight
iNode = iNextNode
lstTree = append(lstTree, iNode)
}
}
return iSum
}
func FindMinNeibor(lstTree []int) []int {
//找到下一个要加到生成树种的节点
//参数:lstTree生成树种的节点
//返回值:lstResult[0] 下一个要加到生成树种的节点, lstResult[1] 代价
iMin := 0
iNextNode := -1
for _, iNode := range lstTree {
for iNeiborNode, iWeight := range lstGrap[iNode] {
if (iMin == 0 || iWeight < iMin) && !IsContain(lstTree, iNeiborNode) && iWeight != 0 {
iMin = iWeight
iNextNode = iNeiborNode
}
}
}
fmt.Printf("return:%v\n", iNextNode)
lstResult := []int{iNextNode, iMin}
return lstResult
}
func IsContain(lstData []int, value int) bool {
// 判断元素是否在列表中
for _, val := range lstData {
if val == value {
return true
}
}
return false
}
func InitGrap() {
// 初始化图
lstGrap = [9][9]int{
[9]int{0, 3, 0, 0, 0, 4, 0, 0, 0},
[9]int{3, 0, 8, 0, 0, 0, 6, 0, 5},
[9]int{0, 8, 0, 12, 0, 0, 0, 0, 0},
[9]int{0, 0, 12, 0, 10, 0, 14, 6, 0},
[9]int{0, 0, 0, 10, 0, 18, 0, 1, 0},
[9]int{4, 0, 0, 0, 18, 0, 7, 0, 0},
[9]int{0, 6, 0, 14, 0, 7, 0, 9, 0},
[9]int{0, 0, 0, 6, 1, 0, 9, 0, 0},
[9]int{0, 5, 2, 11, 0, 0, 0, 0, 0}}
}
func main() {
InitGrap()
iSum := Prim()
fmt.Printf("\n最小生成树路径和:%v", iSum)
}
存在的问题
如果有知道的可以在评论区留言
-
go语言我不知道该如何判断元素是否在列表中,只好遍历来判断,不知道是否有内置的方法判断
-
无穷大如何定义?