卡码网 53.寻宝(prim算法, 牙拆线+看电影,玩一天804)

7 阅读2分钟

题目

image.png

image.png

26年8月4日(首刷看解)

package main
import "fmt"
var(
    v,e int
    INF=10001
)
func prim(n int ,graph [][]int)int{
    minDist:=make([]int,n+1)
    for i:=1;i<=v;i++{
        minDist[i]=INF
    }
    visited:=make([]bool,v+1)//之后到时间系统学一下int,map,slice
    minDist[1]=0
    //寻找距离最小生成树最近的节点
    for i:=1;i<v;i++{
        cur:=-1
        for j:=1;j<=v;j++{
            if !visited[j]&&(cur==-1||minDist[j]<minDist[cur]){
                cur=j
            }
        }
        visited[cur]=true
         //更新minDist距离
        for j:=1;j<=v;j++{
            if !visited[j]&&graph[cur][j]<minDist[j]{
                minDist[j]=graph[cur][j]
            }
        }
        //会覆盖i
    }
    total:=0
    for _,v:=range minDist{
        total+=v
    }
    return total
}
func main(){
    fmt.Scanf("%d %d",&v,&e)
    graph:=make([][]int,v+1)
    for i:=range graph{
        graph[i]=make([]int,v+1)
        for j:=0;j<v+1;j++{
            graph[i][j]=INF
        }//没有初始化为INF
    }
    for i:=0;i<e;i++{
        var v1,v2,val int
        fmt.Scanf("%d %d %d",&v1,&v2,&val)
        graph[v1][v2]=val
        graph[v2][v1]=val
        //无向图 
    }
    res:=prim(v,graph)
    fmt.Println(res)
}

思路

prim算法,着重于节点,用来解决最小生成树的问题。

三部曲

1.寻找距离最小树最近的节点

第一个节点:初始化第一个点任意选一个就行,这里把cur=-1,于是在接下来的比较,cur被赋值为1,在后续的minDist比较中,距离都是INF,所以就第一个节点加入队列。

其他节点:其他节点距离cur的值更新后,进行比较minDist,其中最小的就是距离最小树最近的节点。这里距离最近就是权值,有点像贪心,每一步选局部最优。

外层循环一共要确定n条边。

image.png

2.最近节点加入最小树

加入节点其实就是确立cur,并且标记visited的过程,后续根据cur进行更新距离

3.更新未选入节点距离最小树的距离

更新其实就是判断是否graph[cur][j]<minDist[j]

所以prim算法的核心就是维护minDist,拿到每一步的最优解,而且在每找到最近节点后加入,需要更新minDist(有可能加入cur后最小的距离会更新,也有可能没更新)。从而以节点为核心,找到总权值最小的路线

错误点:没有初始化所有边为INF,无向图没考虑到双向的garph表赋值