为什么Dijkstra的算法有效?

时间:2010-05-18 11:17:28

标签: algorithm

我理解Dijkstra's algorithm是什么,但我不明白为什么会这样。

当选择下一个要检查的顶点时,为什么Dijkstra的算法会选择权重最小的顶点?为什么不随意选择一个顶点,因为算法无论如何都会访问所有顶点?

7 个答案:

答案 0 :(得分:22)

您可以将Djikstra的算法视为注水算法(即修剪的广度优先搜索)。在每个阶段,目标是以尽可能低的成本路径覆盖整个图表的更多部分。假设您在填充区域的边缘有顶点,并按距离列出它们:

v0 <= v1 <= v2 <= v3 ...

是否可能有更便宜的方式来到顶点v1?如果是这样,路径必须通过v0,因为没有未经测试的顶点可能更接近。因此,您检查顶点v0以查看您可以到达的位置,检查通过v0的任何路径是否更便宜(距离任何其他顶点一步之遥)。

如果你以这种方式剥离问题,你可以确保你的距离都是最小值,因为你总能确切地检查那个可能导致最短路径的顶点。要么找到最短路径,要么排除它,然后继续前进到下一个顶点。因此,您可以保证每步消耗一个顶点。

你停下来而不做任何你需要的工作,因为当目的地顶点占据“我最小的”v0位置时你会停止。

让我们看一个简短的例子。假设我们试图通过乘法从112,并且节点之间的成本是您必须乘以的数字。 (我们会将顶点限制为从112的数字。)

我们从1开始,我们可以通过乘以该值到达任何其他节点。因此,节点2的费用为23的费用为3,如果您只需一步,则12费用为12

现在,如果有212的免费链接,2的路径可以(不知道结构)最快到达12。没有,但如果有,它会是最快的。所以我们检查2。我们发现,我们可以4获取费用26获取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.

好的,现在也许我们可以免费从123!更好的检查。我们发现3*2==6因此6的费用是32的费用,而9的费用加3124

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

现在我们尝试56 - 到目前为止没有任何改进。这给我们留下了

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算法的工作原理是部分,因为它利用了节点uw之间包含点{{}的最短路径这一事实1}}还包含从vu以及从vv的最短路径。如果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()