它们其实都是“图”-最小生成树问题(Prim、Kruskal)
生成树的概念
给定一个无向图,如果它的某个子图中任意两个顶点都相互连通并且是一棵树,那么这棵树就叫做生成树。如果边上有权值,那么使得边权和最小的生成树叫做最小生成树。
最小生成树问题
Prim算法
Prim算法与Dijkstra算法类似,从某个顶点出发,不断添加边的算法。
思想:
- 维护一个当前顶点集合到其他顶点的最小权值数组。
- 找到最小权值的顶点
- 更新最小权值数组
package main
import "fmt"
func main() {
var V int // 顶点个数
cost := make([][]int, V)
mincost := make([]int, V)
used := make([]bool, V)
for i := range cost {
cost[i] = make([]int, V)
}
mincost[0] = 0
res := 0
for {
v := -1
for u := 0; u < V; u++ {
if !used[u] && (v == -1 || mincost[u] < mincost[v]) {
v = u
}
}
if v == -1 {
break
}
used[v] = true
res += mincost[v]
for u := 0; u < V; u++ {
if mincost[u] > cost[v][u] {
mincost[u] = cost[v][u]
}
}
}
fmt.Println(res)
}
Kruskal算法
每次取权值最小的边
package main
import (
"fmt"
"sort"
)
var par = []int{
}
var rank = []int{
}
// 初始化n个元素
func initUnionFind(n int) {
for i := 0; i < n; i++ {
par[i] = i
rank[i] = i
}
}
// 查询x的根节点
func find(x int) int {
if par[x] == x {
return x
} else {
par[x] = find(par[x])
return par[x]
}
}
// 合并x和y所属的集合
func unite(x, y int) {
x, y = find(x), find(y)
if x == y {
return
}
if rank[x] < rank[y] {
par[x] = y
} else {
par[y] = x
if rank[x] == rank[y] {
rank[x]++
}
}
}
// 判断x和y是否属于同一个集合
func same(x, y int) bool {
return find(x) == find(y