Kruskal算法用于为给定图生成最小生成树.Kruskal算法按边权重的递增顺序对所有
边进行排序..并且仅当所选边不形成任何循环时才继续向树中添加节点.此外.它首先
选择权重最低的边.最后选择权重最高的边.可以说Kruskal算法作出了局部最优的选
择.旨在找到全局最优解.
1.步骤:
按权重的非递减顺序对所有边进行排序.
选择权重最小的边.检查它是否与目前形成的生成树形成循环.如果为形成循环.则添加
到树中.否则.丢弃它.
重复步骤2.直到生成树中有v-1条边.当生成树中有v-1条边时.则形成最小生成树.
2.使用场景:
网络设计:
该算法可用于设计高效且具有成本效益的通信网络.如有线电视网络 互联网络和电话
网络等.
交通网络:
该算法可用于寻找交通网络(如公路 铁路和航空)的最佳路线.
电路设计:
该算法可用于设计电路板和接线图.其中需要优化不同组件之间的连接以最小化总成本.
资源分配:
该算法可用于分配网络或系统资源.如分配带宽 分配存储空间或将任务分配给处理器.
3.实现:
3.1方法:
package data
import "sort"
// 加权图边.
type Edge struct {
Src int
Dst int
Cost int
}
func Kruskal(v int, es []Edge) (int, []Edge) {
sort.Slice(es, func(i, j int) bool {
return es[i].Cost < es[j].Cost
})
cost := 0
mst := make([]Edge, 0)
u := newSet(v)
for _, e := range es {
if !u.IsSameSet(e.Src, e.Dst) {
u.Union(e.Src, e.Dst)
mst = append(mst, e)
cost += e.Cost
}
}
return cost, mst
}
type UnionSet struct {
p []int
r []int
}
// 给定的两个元素包含在一个集合中.则返回true.
func (uf *UnionSet) IsSameSet(a, b int) bool {
a = uf.find(a)
b = uf.find(b)
return a == b
}
func (uf *UnionSet) Union(a, b int) {
if uf.r[a] > uf.r[b] {
uf.p[b] = a
} else {
uf.p[a] = b
if uf.r[a] == uf.r[b] {
uf.r[a]++
}
}
}
// 查找返回根元素.
func (uf *UnionSet) find(x int) int {
if uf.p[x] != x {
uf.p[x] = uf.find(uf.p[x])
}
return uf.p[x]
}
func newSet(size int) *UnionSet {
uf := new(UnionSet)
uf.p = make([]int, size)
uf.r = make([]int, size)
for i := range uf.p {
uf.p[i] = i
uf.r[i] = 1
}
return uf
}
3.2main方法:
func main() {
edges := []data.Edge{{0, 1, 10},
{0, 2, 6},
{0, 3, 5},
{1, 3, 15},
{2, 3, 4}}
v := 5
res1, res2 := data.Kruskal(v, edges)
fmt.Println(res1, res2)
}
4.实战:
4.1方法:
func FindCriticalAndPseudo(n int, edges [][]int) [][]int {
//将索引添加到切片.
for i := range edges {
edges[i] = append(edges[i], i)
}
sort.Slice(edges, func(i, j int) bool {
return edges[i][2] < edges[j][2]
})
//使用Kruskal查找mst.
minWeight := mstWeight(n, edges, -1, -1)
critical := make([]int, 0)
pseudoCritical := make([]int, 0)
for i := range edges {
wgt := mstWeight(n, edges, i, -1)
if wgt == -1 || wgt > minWeight {
critical = append(critical, edges[i][3])
continue
}
wgt = mstWeight(n, edges, -1, i)
if wgt == minWeight {
pseudoCritical = append(pseudoCritical, edges[i][3])
}
}
sort.Ints(critical)
sort.Ints(pseudoCritical)
return [][]int{critical, pseudoCritical}
}
func mstWeight(n int, edges [][]int, skipIdx int, forceIncludeIndex int) int {
dsu := newUnionSet(n)
var weight int
if forceIncludeIndex != -1 {
e := edges[forceIncludeIndex]
dsu.union(e[0], e[1])
weight += e[2]
}
for i, edge := range edges {
if i == skipIdx {
continue
}
a, b := edge[0], edge[1]
ra, rb := dsu.find(a), dsu.find(b)
if ra == rb {
continue
}
dsu.union(a, b)
weight += edge[2]
}
a := dsu.find(0)
for i := range dsu.parent[1:] {
if dsu.find(1+i) != a {
return -1
}
}
return weight
}
func newUnionSet(n int) *NewUnionSet {
dsu := &NewUnionSet{
parent: make([]int, n),
size: make([]int, n),
}
for i := 0; i < n; i++ {
dsu.parent[i] = i
dsu.size[i] = 1
}
return dsu
}
type NewUnionSet struct {
parent []int
size []int
}
func (d *NewUnionSet) find(a int) int {
if d.parent[a] == a {
return a
}
root := d.find(d.parent[a])
d.parent[a] = root
return root
}
func (d *NewUnionSet) union(a, b int) {
a = d.find(a)
b = d.find(b)
if a != b {
if d.size[a] < d.size[b] {
a, b = b, a
}
d.parent[b] = a
d.size[a] += d.size[b]
}
}
4.2main方法:
func main() {
edges := [][]int{{0, 1, 1},
{1, 2, 1},
{2, 3, 2},
{0, 3, 2},
{0, 4, 3},
{3, 4, 3},
{1, 4, 6}}
n := 5
pseudo := data.FindCriticalAndPseudo(n, edges)
fmt.Println(pseudo)
}
字字皆凉意.
如果大家喜欢我的分享的话.可以关注我的微信公众号
念何架构之路