1
# Dijkstra's algorithm for shortest paths
2
# David Eppstein, UC Irvine, 4 April 2002
4
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117228
5
from priodict import priorityDictionary
7
def dijkstra(G,start,end=None):
9
Find shortest paths from the start vertex to all
10
vertices nearer than or equal to the end.
12
The input graph G is assumed to have the following
13
representation: A vertex can be any object that can
14
be used as an index into a dictionary. G is a
15
dictionary, indexed by vertices. For any vertex v,
16
G[v] is itself a dictionary, indexed by the neighbors
17
of v. For any edge v->w, G[v][w] is the length of
18
the edge. This is related to the representation in
19
<http://www.python.org/doc/essays/graphs.html>
20
where Guido van Rossum suggests representing graphs
21
as dictionaries mapping vertices to lists of neighbors,
22
however dictionaries of edges have many advantages
23
over lists: they can store extra information (here,
24
the lengths), they support fast existence tests,
25
and they allow easy modification of the graph by edge
26
insertion and removal. Such modifications are not
27
needed here but are important in other graph algorithms.
28
Since dictionaries obey iterator protocol, a graph
29
represented as described here could be handed without
30
modification to an algorithm using Guido's representation.
32
Of course, G and G[v] need not be Python dict objects;
33
they can be any other object that obeys dict protocol,
34
for instance a wrapper in which vertices are URLs
35
and a call to G[v] loads the web page and finds its links.
37
The output is a pair (D,P) where D[v] is the distance
38
from start to v and P[v] is the predecessor of v along
39
the shortest path from s to v.
41
Dijkstra's algorithm is only guaranteed to work correctly
42
when all edge lengths are positive. This code does not
43
verify this property for all edges (only the edges seen
44
before the end vertex is reached), but will correctly
45
compute shortest paths even for some graphs with negative
46
edges, and will raise an exception if it discovers that
47
a negative edge has caused it to make a mistake.
50
D = {} # dictionary of final distances
51
P = {} # dictionary of predecessors
52
Q = priorityDictionary() # est.dist. of non-final vert.
60
vwLength = D[v] + G[v][w]
64
"Dijkstra: found better path to already-final vertex"
65
elif w not in Q or vwLength < Q[w]:
71
def shortest_path(G,start, end):
73
Find a single shortest path from the given start vertex
74
to the given end vertex.
75
The input has the same conventions as Dijkstra().
76
The output is a list of the vertices in order along
80
D,P = dijkstra(G,start,end)
85
if end == start: break
90
def closest(distances, pending):
93
distance = distances[node]
96
if closest is None or distance < closest[1]:
97
closest = (node, distance)
100
def relax(node, distances, graph):
101
for child in graph[node]:
102
new_distance = distances[node] + graph[node][child]
103
if distances[child] is None or distances[child] < new_distance:
104
print "setting %s to %d, from %s(%d)" % (child, new_distance, node,
106
distances[child] = new_distance
108
def farthest_node(graph, start):
111
pending = set(graph.keys())
113
distances[node] = None
115
while len(done) < len(distances):
116
node = closest(distances, pending)
119
relax(node, distances, graph)
121
distfirst = [(d, n) for n, d in distances.iteritems()]
122
return distfirst[-1][1]
124
def farthest_nodes_ab(graph, start):
128
while len(lines) > 0:
131
for child in graph[line]:
132
if child not in predecessors:
134
predecessors[child] = line
136
endpoints[line] = None
139
for endpoint in endpoints:
144
node = predecessors[node]
145
distances.append((len(path), endpoint))
146
distances.sort(reverse=True)
147
return [d[1] for d in distances]
150
2
def max_distance(node, ancestors, distances):
151
3
"""Calculate the max distance to an ancestor. Return None if"""