我理解Dijkstra's algorithm是什么,但我不明白为什么会这样。
当选择下一个要检查的顶点时,为什么Dijkstra的算法会选择权重最小的顶点?为什么不随意选择一个顶点,因为算法无论如何都会访问所有顶点?
答案 0 :(得分:22)
您可以将Djikstra的算法视为注水算法(即修剪的广度优先搜索)。在每个阶段,目标是以尽可能低的成本路径覆盖整个图表的更多部分。假设您在填充区域的边缘有顶点,并按距离列出它们:
v0 <= v1 <= v2 <= v3 ...
是否可能有更便宜的方式来到顶点v1
?如果是这样,路径必须通过v0
,因为没有未经测试的顶点可能更接近。因此,您检查顶点v0
以查看您可以到达的位置,检查通过v0
的任何路径是否更便宜(距离任何其他顶点一步之遥)。
如果你以这种方式剥离问题,你可以确保你的距离都是最小值,因为你总能确切地检查那个可能导致最短路径的顶点。要么找到最短路径,要么排除它,然后继续前进到下一个顶点。因此,您可以保证每步消耗一个顶点。
你停下来而不做任何你需要的工作,因为当目的地顶点占据“我最小的”v0
位置时你会停止。
让我们看一个简短的例子。假设我们试图通过乘法从1
到12
,并且节点之间的成本是您必须乘以的数字。 (我们会将顶点限制为从1
到12
的数字。)
我们从1
开始,我们可以通过乘以该值到达任何其他节点。因此,节点2
的费用为2
,3
的费用为3
,如果您只需一步,则12
费用为12
。
现在,如果有2
到12
的免费链接,2
的路径可以(不知道结构)最快到达12
。没有,但如果有,它会是最快的。所以我们检查2
。我们发现,我们可以4
获取费用2
,6
获取3
,依此类推。因此,我们有一个类似的成本表:
3 4 5 6 7 8 9 10 11 12 // Vertex
3 4 5 5 7 6 9 7 11 8 // Best cost to get there so far.
好的,现在也许我们可以免费从12
到3
!更好的检查。我们发现3*2==6
因此6
的费用是3
加2
的费用,而9
的费用加3
, 12
加4
。
4 5 6 7 8 9 10 11 12
4 5 5 7 6 6 7 11 7
足够公平。现在我们测试4
,我们看到我们可以获得额外8
2
和额外12
3
。同样,到达12
的费用不会超过4
+ 3
= 7
:
5 6 7 8 9 10 11 12
5 5 7 6 8 7 11 7
现在我们尝试5
和6
- 到目前为止没有任何改进。这给我们留下了
7 8 9 10 11 12
7 6 8 7 11 7
现在,我们第一次看到前往8
的费用少比到达7
的费用,所以我们最好检查一下没有一些免费的方式从12
到达8
。没有 - 根本没有办法达到整数 - 所以我们把它扔掉了。
7 9 10 11 12
7 8 7 11 7
现在我们看到12
与任何路径一样便宜,因此到达12
的费用必须为7
。如果我们一直跟踪到目前为止最便宜的路径(只有当它完全更好时才更换路径),我们会发现3*4
是第一个最便宜的方式12
。
答案 1 :(得分:5)
Dijkstra算法选择迄今为止路径成本最低的顶点,因为通过任何其他顶点的路径至少与通过顶点的路径成本最低。
访问任何其他顶点,因此,如果它更昂贵(这很可能)将不仅需要访问其他顶点,而且还需要访问迄今为止路径成本最低的顶点,因此您必须访问更多顶点在找到最短路径之前。事实上,如果你这样做,最终会得到Bellman-Ford algorithm。
我还应该补充一点,顶点没有权重,它是有权重的边。给定顶点的关键是到目前为止从源顶点到该顶点的最短路径的成本。
答案 2 :(得分:4)
Dijsktra算法的工作原理是部分,因为它利用了节点u
和w
之间包含点{{}的最短路径这一事实1}}还包含从v
到u
以及从v
到v
的最短路径。如果u到v之间存在较短的东西,那么它就不是最短的路径。
要真正理解Dijkstra算法的工作原理,请查看dynamic programming的基础知识,听起来很难,但理解原理非常容易。
答案 3 :(得分:0)
它喜欢贪婪的策略。我的英语不好。它是谷歌翻译的。如果你不明白,我很抱歉。
Dijkstra算法,从S到最短路径长度的所有顶点的G。 我们假设V中每个G的顶点都有一个标志L(V),它是一个数字,或者是∞。假设P是G的顶点集合,P包含S,以满足:
A)如果V是P,那么L(V)从V S到最短路径的长度,并且这种V从S到最短路径的存在:P中顶点上的路径
B)如果V不属于P,则从S到V的L(V)满足最短路径长度的以下限制:V是唯一路径P不属于顶点。
我们可以使用归纳来证明P Dijkstra算法符合上述集合的定义:
1)当P = 1中的元素个数时,P对应于算法中的第一步,P =(S),显然是满足的。
2)假设P为k,元素数量,P满足上述定义,请参见第三步下面的算法
3)P in和第一个找出的最小顶点U没有标记,标记为L(U),可以证明从最短路径外的U到U的U,除了P不包含元素不属于。
因为除了U之外还有其他顶点之外,那么到S,P1,P2 ... Pn,Q1,Q2 ... Qn,U(P1,P2 ... Pn的最短路径是P; Q1 ,Q2,...... Qn不属于P),从B)的性质来看,最短路径长度L(Q1)+ PATH(Q1,U)> L(U)。
大于S,P1,P2 ...通道长度L(U)的Pn,U不是最短路径。因此,从最短路径的S到U的U,除了P不包含不属于U的元素从S到L(U)的最短路径的长度给出。
U以P'的形式添加到P中,显然是P'以满足A)的性质。
取V不属于P',显然不属于VP,那么从S到V除了最短路径并且满足路径中P'以外的所有顶点有两种可能性,i)包含U ,ii)不包含美国。
在i)S,P1,P2 ... Pn,U,V = L(U)+ W(U,V)
ii)S,P1,P2 ... Pn,V = L(V)
显然,两个是从S中的最小V给出以满足最小访问量,并且所有顶点的外部添加都是V P'的长度。
P'中给出的算法的第三步,其中k + 1个元素符合A),B)。
通过归纳命题可能允许。
这是the source。
答案 4 :(得分:0)
它首先检查具有最低权重的路径,因为这很可能(没有附加信息)减少检查的路径数。例如:
a->b->c cost is 20 a->b->d cost is 10 a->b->d->e cost is 12
如果目标是从a到e,我们甚至不需要检查以下成本:
a->b->c->e
因为我们知道它至少20,所以我们知道它不是最优的,因为已经存在另一条成本为12的路径。您可以通过首先检查最低权重来最大化此效果。这与minimax在国际象棋和其他游戏中如何工作以减少游戏树的分支因素类似(相同?)。
答案 5 :(得分:0)
Dijkstra算法是一种贪心算法,它遵循问题求解启发式,在每个阶段做出局部最优选择,希望找到全局最优。
答案 6 :(得分:0)
为了理解这个算法的基本概念,我为你编写了这段代码。有一个解释它是如何工作的。
graph = {}
graph["start"] = {}
graph["start"]["a"] = 6
graph["start"]["b"] = 2
graph["a"] = {}
graph["a"]["finish"] = 1
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["finish"] = 5
graph["finish"] = {}
infinity = float("inf")
costs = {}
costs["a"] = 6
costs["b"] = 2
costs["finish"] = infinity
print "The weight of each node is: ", costs
parents = {}
parents["a"] = "start"
parents["b"] = "start"
parents["finish"] = None
processed = []
def find_lowest_cost_node(costs):
lowest_cost = float("inf")
lowest_cost_node = None
for node in costs:
cost = costs[node]
if cost < lowest_cost and node not in processed:
lowest_cost = cost
lowest_cost_node = node
return lowest_cost_node
node = find_lowest_cost_node(costs)
print "Start: the lowest cost node is", node, "with weight",\
graph["start"]["{}".format(node)]
while node is not None:
cost = costs[node]
print "Continue execution ..."
print "The weight of node {} is".format(node), cost
neighbors = graph[node]
if neighbors != {}:
print "The node {} has neighbors:".format(node), neighbors
else:
print "It is finish, we have the answer: {}".format(cost)
for neighbor in neighbors.keys():
new_cost = cost + neighbors[neighbor]
if costs[neighbor] > new_cost:
costs[neighbor] = new_cost
parents[neighbor] = node
processed.append(node)
print "This nodes we researched:", processed
node = find_lowest_cost_node(costs)
if node is not None:
print "Look at the neighbor:", node
# to draw graph
import networkx
G = networkx.Graph()
G.add_nodes_from(graph)
G.add_edge("start", "a", weight=6)
G.add_edge("b", "a", weight=3)
G.add_edge("start", "b", weight=2)
G.add_edge("a", "finish", weight=1)
G.add_edge("b", "finish", weight=5)
import matplotlib.pyplot as plt
networkx.draw(G, with_labels=True)
plt.show()