BFS_or_Djiskra+优先队列_5211_ 概率最大的路径 - 197场周赛第3题

题目描述

在这里插入图片描述
在这里插入图片描述

思路

方法1 - BFS

  • 关键点是: 当我们遍历到一个节点时,如果节点没有遍历过,那么可以继续遍历;如果遍历过节点,但是上次遍历时的概率比当先小,这个时候是需要重复遍历的(其实是贪心算法)
class Solution:
    def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start: int, end: int) -> float:
        if not edges or not edges[0]: return 0

        # 构造节点邻接表
        st_maps = collections.defaultdict(list)
        for i, (s, e) in enumerate(edges):
            st_maps[s].append((e, succProb[i]))
            st_maps[e].append((s, succProb[i]))

        ans = 0
        queue = collections.deque([(start, 1)])
        visited = {start: 0}  # value为已经遍历到该节点最大的概率值(还可能存在其他路径到该节点的概率更大的情况)
        while queue:
            # 当前节点
            cur_node, cur_prob = queue.popleft()
            for next_node, p in st_maps[cur_node]:
                # 下一个待遍历的节点
                next_prob = cur_prob * p
                if next_node == end:
                    ans = max(ans, next_prob)
                    continue

                # 剪枝和去重:如果下一个待遍历节点的概率大于ans && (该节点为遍历过 或 遍历过该节点但是上次的概率比现在小)
                if next_prob > ans and (next_node not in visited or visited[next_node] < next_prob):
                    visited[next_node] = next_prob
                    queue.append((next_node, next_prob))
        return ans

法2 - Dijkstra+优先队列

class Solution:
    def maxProbability(self, n: int, edges, succProb: List[float], start: int, end: int) -> float:
        
        # 用于标记节点是否已经访问过
        vis = [0] * n
        
        # 用于标记已经访问过的节点个数
        cnt = 0
        
        import heapq
        # 最大堆,用于dijkstra里每次寻找当前未访问的节点中最大概率的节点
        # 如果用普通队列,会超时,因为查找最大的时间复杂度是O(n)
        q = []
        heapq.heappush(q, (-1, start))
        
        # 生成graph,数据格式为: {node1 : [(node2, prob_1_2), (node3, prob_1_3)], node2: [(node1: prob_1_2), (node3: prob_2_3)]}
        graph = {}
        for i, item in enumerate(edges):
            s, e, p = item[0], item[1], succProb[i]
            
            graph.setdefault(s, []).append((e, p))
            graph.setdefault(e, []).append((s, p))    
        
        # 循环查找每个节点
        while cnt < n:
            # 队列为空,还没有找到,说明没有路径,即end 和 start 未连通
            if not q:
                return 0
            
            # 从最大堆中获取当前还没遍历过的节点里,概率最大的节点
            maxProb, maxIdx = heapq.heappop(q)
            while vis[maxIdx]:
                maxProb, maxIdx  = heapq.heappop(q)
            
            # 如果maxIdx不在队列中 - 说明 start是孤立节点
            if maxIdx not in graph:
                return 0
            
            # 找到终点,结束循环
            if maxIdx == end:
                return -maxProb
            
            # 将该节点设置为已访问状态
            vis[maxIdx] = True
            cnt += 1
            
            # 对于所有邻居节点,如果没有被访问过,放入队列
            for e in graph[maxIdx]:
                if not vis[e[0]]:
                    heapq.heappush(q, (maxProb * e[1], e[0]))
                 
        return 0

Reference

1
2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值