dijkstra堆优化代码详解

阅读堆优化代码之前,首先要弄懂dijkstra的基础思路,建议b站找个视频看下图解过程,二十分钟足矣。其中算法核心有以下几点:

  1. 将所有点分为已确定最短路径的点集 N v i s {N_{vis}} Nvis和未确定的点集 N u n v i s N_{unvis} Nunvis,以及一个 N v i s {N_{vis}} Nvis N u n v i s N_{unvis} Nunvis的边集(每一条边至少保存目标id以及到源点 S S S的距离)。
  2. 初始化:将源点S初始化到 N v i s {N_{vis}} Nvis中,并将

在这里插入图片描述
以上虽然是求概率最大路径,和通常求最短路径相反,但思路相同,重载比较运算符即可。
堆优化的最关键一点,是要明白堆顶(也就是代码中的优先队列top元素)如果没有被vis标记过,则一定是下一个到源点确定为最大概率的点。


struct Node {
    double p; // 该结点到源点的当前最大概率
    int node_id; 
    bool operator < (const Node &b) const {
        return p < b.p;
    } //使用重载小于运算,从而利用优先队列模板
};

class Solution {
public:
    double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start, int end) {
        vector<vector<Node>> g(n, vector<Node>{});  //邻接表存储
        for(int i = 0; i < edges.size(); ++i) {
            g[edges[i][0]].push_back(Node{succProb[i], edges[i][1]});
            g[edges[i][1]].push_back(Node{succProb[i], edges[i][0]});
        }
		
        vector<bool> vis(n, false);  //这个数组记录已经确定最大概率的node
        priority_queue<Node> q;
        q.push(Node{1., start});  //初始化源点
        
        while (!q.empty()) {
            Node t = q.top();
            if (vis[t.node_id]) {q.pop(); continue;}  //之前已经找到最大概率的node, 跳过这个点
            if (t.node_id == end) break; //确定目标点最大概率,终止循环
            vis[t.node_id] = true; //堆顶一定为下一个确定最大概率的点
            q.pop();
            for (Node &n: g[t.node_id]) {
                if (vis[n.node_id]) continue;
                double new_p = t.p * n.p;
                if (new_p > 0) {
                    q.push(Node{new_p, n.node_id}); //优先队列中可能有多个node_id相同的Node,但这并不影响大局
                }
            }
        }
        if (q.empty())  //目标和原点不连通
            return 0.;
        else 
            return q.top().p;
        
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值