zoukankan      html  css  js  c++  java
  • 最短路径问题

    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);
    //                 }
    //             }
    //         }
    
    // }
  • 相关阅读:
    ASP.NET MVC EF4.1
    RabbitMQ Boot Step
    图书商城项目总论
    CodeSharp.EventSourcing框架介绍如何实现异步事件订阅
    asp.net的cms 原理篇
    异步编程:线程概述及使用
    2012
    CodeSharp.EventSourcing框架介绍
    最近开发的一个文档管理系统
    团队项目开发
  • 原文地址:https://www.cnblogs.com/wsZzz1997/p/14772352.html
Copyright © 2011-2022 走看看