错误是认为“第一种方式,最好的方式”,这是不正确的。在此算法中,您可以更新到达顶点的成本(如果成本较低的话)。
节点分为已访问、未访问、可用、不可用。
我们不能考虑visited,因为如果,他的值最小,而且我们没有负值边(见算法假设)你就找不到更好的方法。
未访问的都是另一回事,可能我们实际上无法走到所有这些地方。
可用的顶点都是未访问的,我们现在可以访问。(我认为,不可用是显而易见的。)
开始时可用的只有第一个顶点。我们可以遵循一个简单的模式。
一步步:
- 从所有(实际)可用的顶点中获取最便宜的顶点。这应该由优先级队列完成。最简单的解决方案是二叉堆(O(|E| log |V|)),但是如果您考虑性能,可以使用斐波那契堆(O(|E|+|V|log|V|)),如果不要,可能,但不推荐的方法是使用数组(O(|V|^2+E))。这应该是根。
-对于当前节点,您应该更新所有未访问的邻居(未访问的,不可用的(为什么,见上文))行程成本如果((当前节点的成本+连接它们的边缘的权重,与邻居)<(实际成本从开始节点到达邻居))。当您将不可用更改为可用时,您必须将更改的元素添加到优先级队列中。当你更新一个节点的成本时,你应该升级堆,不要忘记。
- 将实际节点标记为已访问。将他从优先级队列中删除(永久地,它被访问过),在最小堆中它是 delete_root 操作。
- 重复直到队列不为空。
在您的示例中,它可能如下所示:
Number - 实际上是节点之间路径的最低总权重(第一个和最后一个)。
星星 - 节点被访问,这个成本永远不会改变。
Dash - 节点此时不可用。
| a | b | c | d |
-----------------
| 0 | - | - | - | <-- Available is only a.
-----------------
|*0*| 1 | 2 | - | <-- You can go to b and c.
-----------------
|*0*|*1*| 2 | 16| <-- b was cheaper, you updated costs from this vertex.
-----------------
|*0*|*1*|*2*| 3 | <-- You didn't stop, and find less costly way!
-----------------
|*0*|*1*|*2*|*3*| <-- Work done, the last vertex visited.
-----------------
更具体地说,最初可用的只是第一个元素,所以一开始你必须拜访他。完成后,可用的是两个新节点,您应该访问最便宜的(从可用,未访问)。是b。从 b 到 d 是唯一的方式,所以你只升级他的成本(现在 d 可用,但实际方式(成本)可能不是最优的)。再次从可用的顶点中获取最便宜的顶点。是 c,因为访问了 a 和 b,并且 2 小于 16。当您检查此节点时,您会找到更好的方法 d,因此您应该将 d 的成本从 16 更新为 3。访问的最后一个节点 (d) 是正式且无关紧要的移动。您访问了所有顶点,现在您的工作已经完成。