golang实现prim算法,计算最小生成树
1、题目描述
给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。
给定一张边带权的无向图G=(V, E),其中V表示图中点的集合,E表示图中边的集合,n=|V|,m=|E|。
由V中的全部n个顶点和E中n-1条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图G的最小生成树。
输入格式
第一行包含两个整数n和m。
接下来m行,每行包含三个整数u,v,w,表示点u和点v之间存在一条权值为w的边。
输出格式
共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。
2、数据
数据范围
1≤n≤500,
1≤m≤105,
图中涉及边的边权的绝对值均不超过10000。
输入样例:
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出样例:
6
数据图
1、初始所有点的距离为正无穷,就是代码中的0x3f3f3f3f等于1061109567
2、以第一个点为最初点,绿色表示选中,进入到最小生成树中
3、以第一个更新其他与之连通的点的距离
4、依次迭代
5、最后的最小生成树
3、朴素prim算法步骤时间复杂度O(n^2)
1、先初始化所有点距离为正无穷
2、迭代n次,依次用到集合的最小点更新剩余点距离
3、将已经确定的点加入到st集合中,st数组为一个bool类型
4、代码实现
/*
该图是稠密图,使用邻接矩阵
*/
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
const (
N = 510
INF = 0x3f3f3f3f
)
var (
n, m int
dist [N]int
g [N][N]int
st [N]bool
)
func readLine(r *bufio.Reader) []int {
s, _ := r.ReadString('\n')
ss := strings.Fields(s)
res := make([]int, len(ss))
for i, v := range ss {
res[i], _ = strconv.Atoi(v)
}
return res
}
func prim() int {
// 初始化距离集合 dist
for i := 0; i < N; i++ {
dist[i] = 0x3f3f3f3f
}
// 迭代n次
res := 0 //res 存储最小生成树的大小即边的长度总和
for i := 0; i < n; i++ {
// 找到集合外距离最短的点
t := -1
for j := 1; j <= n; j++ {
if !st[j] && (t == -1 || dist[t] > dist[j]) {
t = j
}
}
// 迭代结束,此时的t就是距离最小点
// 情况一:图上的点不连通,不能组成最小生成树
if i > 0 && dist[t] == INF {
return INF
} // 如果不是第一个点并且最小店的距离是正无穷,则表示图是不连通的
if i > 0 {
res += dist[t]
} // 如果不是第一个点,这个t就表示当前点到集合某一个点的最小距离
// 用最小距离点更新其他跟 "现阶段形成的生成树" 的最短距离,
//注意更新的顺序,自环是不应该被加到最小生成树,所以,为了避免自环加入最小生成树,提前更新res
for j := 1; j <= n; j++ {
dist[j] = min(dist[j], g[t][j]) // 此步骤注意是dijkstra的区别,
}
st[t] = true
}
return res
}
func min(a, b int) int {
if a >= b {
return b
} else {
return a
}
}
func main() {
r := bufio.NewReader(os.Stdin)
input := readLine(r)
n, m = input[0], input[1]
//fmt.Scanf("%d%d\n", &n, &m)
// 初始化距离
for i := 0; i < N; i++ {
for j := 0; j < N; j++ {
if i == j {
g[i][j] = 0
} else {
g[i][j] = 0x3f3f3f3f
}
}
}
//
for m > 0 {
m--
in := readLine(r)
a, b, c := in[0], in[1], in[2] //输入
g[a][b] = min(g[a][b], c)
g[b][a] = g[a][b] // 无向图
}
t := prim()
if t == INF {
fmt.Println("impossible")
} else {
fmt.Println(t)
}
}