• Paul Shan
    2022-01-18
    Dijkstra 算法是逐步构建最短路径树,树中的节点的最短距离不依赖于树外节点,这样才可以一个节点加入最短路径树之后,距离不再改变。负权节点的存在会让加入最短路径树的节点的真实最短路径会因为不在树中的节点而改变,整个算法也就无效了。 如果用最小堆作为数据结构选择最短路径,可以让内存循环的复杂度降为lg V,最终的复杂度可以降为(V+E)lg V

    作者回复: 说的非常好耶! 大佬加个wx吧: constant_variation

    
    3
  • ZeroIce
    2022-02-14
    有时候在想:负权边的意义是什么? 应用场景在哪里?🤪

    作者回复: 非常不错的问题。 事实上,在现实生活中有许多能用图抽象的问题都会用到负权边。比如,我们将边定义成到达某个状态所需要的开销;有时候我们需要花费一定的费用到达某个状态;而有的时候会有人支付我们一定的费用。一个很好的例子就是某个司机开往某些地方能赚到一定钱或者支付一定的公路费用。 如果我们为了求出从A点出发到B点的最小成本;当走过某段路可以获得收入的时候,该边就可以被抽象为负权边。

    
    1
  • 到道可道
    2022-03-06
    Dijkstra的Java实现 private int dijkstra(List<int[]>[] graph, int src, int k, int dst) { // 从起点src到达节点i的最短路径权重为distTo[i] int[] distTo = new int[graph.length]; // 定义:从起点src到节点i,至少要经过nodeNumTo[i]个节点 int[] nodeNumTo = new int[graph.length]; Arrays.fill(distTo, Integer.MAX_VALUE); Arrays.fill(nodeNumTo, Integer.MAX_VALUE); // base case distTo[src] = 0; nodeNumTo[src] = 0; // 优先队列,costFromSrc较小的排在前面 Queue<State> pq = new PriorityQueue<>((a, b) -> a.costFromSrc - b.costFromSrc); // 从起点src开始进行BFS pq.offer(new State(src, 0, 0)); while (!pq.isEmpty()) { State curState = pq.poll(); int curId = curState.id; int curCostFromSrc = curState.costFromSrc; int curNodeNumFromSrc = curState.nodeNumFromSrc; if (curId == dst) { // 找到最短路径 return curCostFromSrc; } if (curNodeNumFromSrc == k) { // 中转次数耗尽 continue; } // 将curId 的相邻节点装入队列 for (int[] neighbor : graph[curId]) { int nextId = neighbor[0]; int costToNextNode = curCostFromSrc + neighbor[1]; // 中转次数 int nextNodeNumFromSrc = curNodeNumFromSrc + 1; // 更新dp table if (distTo[nextId] > costToNextNode) { distTo[nextId] = costToNextNode; nodeNumTo[nextId] = nextNodeNumFromSrc; } // 剪枝 if (costToNextNode > distTo[nextId] && nextNodeNumFromSrc > nodeNumTo[nextId]) { continue; } pq.offer(new State(nextId, costToNextNode, nextNodeNumFromSrc)); } } return -1; }
    展开

    作者回复: 写得很好 感兴趣可以来 github.com/wfnuser/Algorithms 提个 pr

    
    