最短路径问题

Posted wsZzz1997

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径问题相关的知识,希望对你有一定的参考价值。

leetcode1514. 概率最大的路径

首先考虑了dfs,1000节点超时,添加记忆化,5000节点超出空间。

邻接矩阵->邻接表(HashMap<node,HashMap>)解决空间问题

dfs仍然超时。

尝试bfs + 普通队列,结果存在误差:由于多次相乘,导致最终结果精度存在问题。

bfs+优先队列+剪枝:将概率大的进行优先排列,保证最短时间找到结果,将小于当前结果的路径排除(剪枝)。

 

class Solution {
    // 最短路径问题:bfs 队列
    // dfs会一条路找到头,因此产生不必要的误差,且剪枝复杂
    // 使用优先队列,优先计算大的通路
    public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
        Map<Integer, Map<Integer, Double>> allEdge = new HashMap<>();

        // 初始化邻接表
        for (int i = 0; i < edges.length; i++) {
            int x = edges[i][0], y = edges[i][1];
            double val = succProb[i];
            Map<Integer, Double> temp;
            if (!allEdge.containsKey(x)) {
                temp = new HashMap<>();
                // temp.put(x, 1.0);
            } else {
                temp = allEdge.get(x);
            }
            temp.put(y, val);
            allEdge.put(x, temp);

            if (!allEdge.containsKey(y)) {
                temp = new HashMap<>();
                // temp.put(y, 1.0);
            } else {
                temp = allEdge.get(y);
            }
            temp.put(x, val);
            allEdge.put(y, temp);
        }
        // 判断边界
        if (!allEdge.containsKey(start) || !allEdge.containsKey(end)) {
            return 0.0;
        }

        // 非记忆法会超时,因此使用一个记忆表记录到达某个节点的最大值
        Map<Integer, Double> memMap = new HashMap<>();
        memMap.put(start, 1.0);

        Set<Integer> used = new HashSet<>();
        used.add(start);

        // Queue<Integer> queue = new ArrayDeque<>();
        Queue<Node> pq = new PriorityQueue<Node>((o1,o2)->{
            if(o2.maxVal-o1.maxVal>0){
                return 1;
            }else{
                return -1;
            }
            });

        pq.add(new Node(start,1.0));
        while (!pq.isEmpty()) {
            Node temp = pq.poll();
            int outNode = temp.node;
            used.add(outNode);
            // 遍历与outNode相连的所有节点
            for (Map.Entry<Integer, Double> relateMap : allEdge.get(outNode).entrySet()) {
                Integer node = relateMap.getKey();
                double val = relateMap.getValue();
                // 如果没来过,或者来过但本次比较大,那么更新
                if (memMap.containsKey(node)) {
                    // 如果当前值比较小
                    double curVal = val * memMap.get(outNode), historyVal = memMap.get(node);
                    if (curVal <= historyVal) {
                        continue;
                    }
                }
                memMap.put(node, val * memMap.get(outNode));
                // 如果node没有被poll过,可以放入,如果当前的node概率小于最终的答案,那么不加入
                if (!used.contains(node) ) {
                    // 当已经找到答案了,就不用往队列里加比答案更小的路径了,因为路径只会递减
                    if(memMap.containsKey(end) && memMap.get(end)>memMap.get(node)){
                        continue;
                    }
                    pq.add(new Node(node,memMap.get(node)));
                }
            }
        }
        if(!memMap.containsKey(end)){
            return 0.0;
        }
        return memMap.get(end);
    }
    class Node{
        int node;
        double maxVal;
        public Node(int node, double maxVal){
            this.node = node;
            this.maxVal = maxVal;
        }
    }

}




// class Solution {
//     public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {
//             Map<Integer,Map<Integer,Double>> allEdge = new HashMap<>();

//             // 初始化邻接表
//             for(int i=0; i<edges.length; i++){
//                 int x=edges[i][0], y = edges[i][1];
//                 double val = succProb[i];
//                 Map<Integer,Double> temp;
//                 if(!allEdge.containsKey(x)){
//                     temp = new HashMap<>();
//                     // temp.put(x,1.0);
//                 }else{
//                     temp = allEdge.get(x);
//                 }

//                 // System.out.println("x="+x+",y="+y+",val="+val);
//                 temp.put(y,val);
//                 allEdge.put(x,temp);

//                 if(!allEdge.containsKey(y)){
//                     temp = new HashMap<>();
//                     // temp.put(y,1.0);
//                 }else{
//                     temp = allEdge.get(y);
//                 }
//                 // System.out.println("y="+y+",x="+x+",val="+val);
//                 temp.put(x,val);
//                 allEdge.put(y,temp);
//             }
//             // 判断边界
//             if(!allEdge.containsKey(start) || !allEdge.containsKey(end) ){
//                 return 0.0;
//             }

//             // 非记忆法会超时,因此使用一个记忆表记录到达某个节点的最大值
//             Map<Integer,Double> memMap = new HashMap<>();

//             Set<Integer> used = new HashSet<>();
//             used.add(start);
//             // 遍历与start相连的所有节点
//             for (Map.Entry<Integer, Double> relateMap : allEdge.get(start).entrySet()) {

//                 Integer node = relateMap.getKey();
//                 double val = relateMap.getValue();

//                 if(!used.contains(node)) {
//                     // 判断是否访问过该node
//                     if(memMap.containsKey(node)){
//                         //如果访问过,且当前节点的值小于曾经访问,那么直接退出
//                         if(val<=memMap.get(node)){
//                             continue;
//                         }
//                     }
//                     memMap.put(node,val);
//                     used.add(node);
//                     dfs(node, end, used, val, allEdge,memMap);
//                     used.remove(node);
//                 }
//             }
//             return maxVal;
//         }
//         double maxVal=0;
//         private void dfs(int curNode, int end, Set<Integer> used, double curVal, Map<Integer, Map<Integer, Double>> allEdge, Map<Integer, Double> memMap) {
//             if(curNode == end){
//                 maxVal = Math.max(maxVal,curVal);
//                 return;
//             }
//             for (Map.Entry<Integer, Double> relateMap : allEdge.get(curNode).entrySet()) {
//                 Integer node = relateMap.getKey();
//                 double val = relateMap.getValue();
//                 // 判断node是否可以通行
//                 if(!used.contains(node)) {
//                     // 判断是否访问过该node
//                     if(memMap.containsKey(node)){
//                         //如果访问过,且当前节点的值小于曾经访问,那么直接退出
//                         if(val*curVal<=memMap.get(node)){
//                             continue;
//                         }
//                     }
//                     memMap.put(node,val*curVal);
//                     used.add(node);
//                     dfs(node, end, used, val*curVal, allEdge, memMap);
//                     used.remove(node);
//                 }
//             }
//         }

// }

 

以上是关于最短路径问题的主要内容,如果未能解决你的问题,请参考以下文章

最短路径问题-Dijkstra(基于图的ADT)

最短路径

多源最短路径--Floyd-Warshall算法

地铁最短路径代码分析

(王道408考研数据结构)第六章图-第四节5:最短路径之弗洛伊德算法(思想代码演示答题规范)

最短路径问题 (最短路模板)