Dijkstra Algorithm基本过程与理解

Series S2: 求一点出发到一点/其他所有点的最短路径

  • 使用条件:边上的权证可以有且不相同但必须为正值

  • Series S1:讲了五个series(见前面的shortest path)

Use Case 1:求出一个点到一个点的最短路径

什么是Dijkstra Algorithm? Best First Search VS Dijkstra

  • Dijkstra:需要有一个Starting Node(题目给的),每一次从到目前为止Cost最低的点出发(Expand),generate所有它的邻居,直到我们Expand到targetNode/所有Node为止!

  • 每当一个点被Expand的时候,它的最短路径(从start到他)就确定了

注意expand& generate

  • expand表示你接下来要访问的

    • 所以你一旦访问了,就表示确定了,所以对于dijkstra来说,每次要访问的(expand),一旦他被访问了,从源头点到该点的最短就确定了

    • 如果记录的每点cost最小,也就是costMark(x) = min Cost(源头,x)

      • min cost(源头,x)= minCost (源头,y) + minCost(y,x)

      • 这个成立的唯一条件,就是cost是正的&cost函数是monotonicity increasing的?

  • generate表示你potential需要访问的点

Greedy算法

  • 不看所有解,我觉得按着某一种方法(aha point)去走,我就得到最优解

  • Greedy算法需要证明,也需要一些灵感!

反证法:会不会有一个被expand的点,其实从源点到它的最短路径没有确定,会在后面的expansion来确定

  • 被Generate的点, A(13), B(15), D(17)

  • Expansion: dis(Src, first_time_C) = 10

  • dis(Src, second_expanded_C) = initial dis from src to the cur node(>= 10) + dis of all the path behind

  • dis(Src, second_expanded_C) > dis(Src, first_time_C)

  • 假设错误

在Dijsktra算法中需要注意

  • 明确你的cost是什么

  • 我们允许一个点被Generate多次,先generate的不一定是最短路径(时间最先!=cost最优)

  • 在有权重图中,Mark Visited at Generation是不一定正确的!!

Cost of Neighbor When Generation

  • dis(src, nei) = dis(src, cur) + weight of (cur, nei)

General Implementation for Dijkstra

这个array版本的实现

  • 缺点:时间肯定不如现代版本的heap/treeMap/treeSet版本实现

  • 优点:元和可读性以及区分性: already_expanded & already_generated

    • if (distances[uIndex] + v.weight < distances[vIndex]) {distances[vIndex] = distance[uIndex] +v.weight};

    • 在这个视线里面,如果一个点被generate多次,不管后面的generate比前面generate得到的结果好还是坏

    • distances[i]只要visited是false i的状态都是already_generated but not yet expand。存储的只会是最优解,一旦visited[i] mark成为true了,说明被expanded

General Implementation for Dijkstra 现代版

Quesiton: 我能不能对于这种被generate的点,直接在PriorityQueue里更新的Entry?

  • 不行,但是可以进行如下操作

  • 优化Java PQ: Search + update: 除非自己实现PriorityQueue, MappedPriorityQueue

  • 选择TreeSet/ TreeMap update: remove + insert

TC&SC

  • TC:普通的遍历算法O(|V| + |E|) ==> O((|V| +|E|) * log |E|)

    • Dijkstra: O(|V+E| * log(E))

    • 除非你做了generation的优化,我保证了每个点至多被generate一次O((V+E)log(V))

  • SC: O(E) or O(V) if you optimize for generation

Use Case 2: 求出从一个点到所有点的最短路径

shortestPaths 里其实存的就是每一个点的最短路径值,而我们只要把遇到target node就return的这个限制条件去掉就好

Use Case 3: Dijkstra在面试中的难点: Multiple-Dimension Node

Example

  • 告诉你地图中所有城市的道路,求从一个start城市出发,走exactly K步能哦租到的所有城市中,总距离和距离当前城市最近的城市

  • graph representation?明白什么是点,什么是边,每个点能去哪些点

    • 为什么不用这个edge不好用,因为没法快速的知道,每个点能去哪些点

    • 比较好的表达方式 adjacency list

      • Map<Node, Map<Node, Integer>> weightGraph

      • Map<Node, List<Node>> unidirectedGraph

小心

  • 走exactly K步能得到的距离和最小 不等与

  • first time走k步的city,因为可能还有些点没有看到

  • K步之内的距离和最小,因为这里说的是我要走K步呀

  • 思考:说白了,因为dijkstra解决的是,某个点,到某个点的最短路径,但是这里的问题没有给出到底到哪个点的?——》所以你就都看step = K——》让每次expand出来的点的step是排好序的

多维度问题的关系

  • 如果你保证,Expand点或者generate点的顺序是单调的,就可以在第一次遇到它就终止算法

  • 如果你能保证你generate点的时候,从小到达的单调递增的来generate,甚至可以在generate mark visited

  • 如果你能保证你expand点的顺序是单调的,那就可以在第一次expand到他的时候终止

Summary

  • Dijkstra算法中每exapnd一次,就确定了从点A到点B的最短路径,往后只能增大不能减少!如果求的是从一个点到所有点的最短路径,也只需要做一次!One to ALL!

  • 是否可以在Generate的时候Mark Visited:不一定

  • 时空复杂度: O(|V| +|E|) log(|E|)

    • 每个点允许被generate多次但是最多只能被expand一次

    • 如果我们自己实现MappedPriorityQueue,那么可以实现Node只能被Generated一次,但是非常复杂情况不如用TreeMap/TreeSet代替更为简洁

  • MappedPriortyQueue:Use case是我们遇到一个已经generated的点的时候,Map找到Node Position,UpdatedValue +上下调整

Last updated