Recently learned some about the shortest path algorithm knowledge, feeling very interesting, but the network many of the algorithm morale and C or C + + implementation way, very few python. So I wanted to go to my own posting Python shortest path tutorial, the right to review their own knowledge.
The shortest path algorithm is a classical problem in graph class, which aims at finding the shortest path from any point to any point in the graph composed of nodes and edges. Today I want to introduce the main floyd-warshall algorithm, Dijkstra algorithm and Bellman-ford. Algorithm. The first one introduces the Floyd-warshall algorithm.
In this figure, the letter represents the vertex, and the number represents the distance between each point. What if we now want to find out the short path from point A to point D. You can, of course, count the distances of each path, and compare them, like this one.
A-d: 8
A-f-e-d: 8
A-b-c-d: 15
A-f-c-d: 7
Finally found that the shortest path is a-f-c-d, this problem can be solved because our diagram is not complex, we can use the exhaustive method to find out all the possibilities. But if we are faced with a 500-point map, how can we be so poor? This time we need the glittering flolyd-warshall algorithm to help us.
However, we need to create a table to save the diagram before we can learn the algorithm. X means no direct arrival between two points
\ |
A |
B |
C |
D |
E |
F |
A |
X |
6 |
X |
X |
X |
1 |
B |
X |
X |
7 |
X |
X |
X |
C |
X |
X |
X |
2 |
X |
X |
D |
X |
X |
X |
X |
X |
X |
E |
2 |
X |
X |
3 |
X |
X |
F |
X |
X |
4 |
X |
4 |
X |
After we get this table, we can easily convert this table to a two-bit array.
Tada~ now really want to introduce the Floyd-warshall algorithm. In fact, the floyed algorithm is simple:
" if the direct path between two points is not the shortest path, there must be one or more points for transit, so that its shortest path ." "
So how do you describe this algorithm in computer language?
For I in range (len (vertex)): for J in Range (Len (dis[j)): To
K in
range (len)):
if dis[i][j] > Dis I [K]+dis[k][j]:
dis[i][j] = dis[i][k]+dis[k][j]
The first and second loops are used very clearly to locate the values of two-dimensional arrays, and to press no table.
The third cycle is used to find the point for the relay, need special attention, the first learning this algorithm I think this algorithm can only find a point as a relay, can not provide a number of points for the relay, the back of a careful look found that my understanding is wrong.
Now suppose we have such a transit program
dis = [
[999, 2, 999, 999, 2, 10],
[999, 999, 999, 999, 999, 6,],
[999, 999, 999, 999, 999, 1],
[999, 999, 999, 999, 999, 999],
[999, 999, 1, 999, 999, 999],
[999, 999, 999, 999, 999, 999],
]
A-f: 10
A-b-F:8
A-E-C-f: 6
We can intuitively find 1, from point A-point f the shortest distance is through the E C two points near the line relay, that this relay in the algorithm is how to achieve it.
First, the computer finds the shortest path from the a-c point, [A][c]>[a][e]+[e][c]
, the a-c is replaced by a bit A-E-C, which means that all the points in the back starting at point A, the C-point relay, start at point A and go through E C two.
Then the computer to find from the a-f, will be in turn all the points between a-f as a relay point one by one attempts, but at the a-c-F this point, as a-c distance has been shorter a-e-C replacement, Friendship a-c-F actually go a-e-c -This path.
The Floyd-warshall algorithm needs to perform three for loops, so its time complexity is O (n^3). Dijkstra Algorithm
Floyd-warshall algorithm is good, but every calculation will be all the points between the shortest path, but sometimes, we may only need a point to the shortest path between the other points, do not need the shortest path between the other points. What to do then. The Dijkstra algorithm comes in handy now.
Dijkstra algorithm through a ' relaxation ' of the idea of a point to another point of the shortest path, specifically how to calculate it, we first look at an example, x means the distance infinitely far:
\ |
A |
B |
C |
D |
E |
F |
A |
X |
6 |
X |
4 |
X |
1 |
B |
5 |
X |
7 |
7 |
X |
X |
C |
X |
X |
X |
2 |
4 |
X |
D |
X |
3 |
5 |
X |
1 |
7 |
E |
2 |
X |
X |
3 |
X |
X |
F |
X |
3 |
4 |
X |
4 |
X |
Then, we create a new list to represent the distance from point A to the other.
\ |
A |
B |
C |
D |
E |
F |
A |
X |
6 |
X |
4 |
X |
1 |
If the sum of the distances of two parts is the minimum, then these two parts should also be the minimum, which is the central idea of the Dijkstra algorithm. To observe the distance from a to the other point, we find from point a
The distance to the F point is the smallest, at which point we call this distance from point A to point F to determine the distance, and then use the F point to relax the other edges.
\ |
A |
B |
C |
D |
E |
F |
A |
X |
4 |
5 |
X |
5 |
1 |
At this point, we found that the transfer through the F-point can be effective simple, a-b, a-c,a-e value, and then now, we are in from A to all points except F, find the point of the smallest distance, the most definite value, for the next one by one times relaxation. Then we found that the a-b point is the shortest distance, so use B to do a relaxation.
\ |
A |
B |
C |
D |
E |
F |
A |
X |
4 |
5 |
11 |
5 |
1 |
Now we've got the result of the relaxation from point B, and now we're going to continue to look for the nearest point, except for B,f's unexpected distance from point A, and then we find that C and E are all 5, so we're going to relax with C.
\ |
A |
B |
C |
D |
E |
F |
A |
X |
4 |
5 |
7 |
5 |
1 |
And then we find that after the C-point relaxation, the distance between the a-d can be shortened, and now we're relaxing with E.
\ |
A |
B |
C |
D |
E |
F |
A |
X |
4 |
5 |
7 |
5 |
1 |
No change, now in the use of the last D point for relaxation, because D is the last point, generally speaking when the last point to relax, the shortest path has actually been found out. So the shortest path for a to each point is
\ |
A |
B |
C |
D |
E |
F |
A |
X |
4 |
5 |
7 |
5 |
1 |
So now, how does this algorithm use Python to describe it?
nodes = (' A ', ' B ', ' C ', ' D ', ', ' E ', ' F ', ' G ') distances = {' B ': {' A ': 5, ' d ': 1, ' G ': 2}, ' A ': {' B ': 5, ' d ': 3, ' E ' :, ' F ': 5}, ' D ': {' B ': 1, ' G ': 1, ' E ': 1, ' A ': 3}, ' G ': {' B ': 2, ' D ': 1, ' C ': 2}, ' C ': {' G ': 2, ' E ': 1, ' F ' :}, ' E ': {' A ': A, ' D ': 1, ' C ': 1, ' F ': 2}, ' F ': {' A ': 5, ' E ': 2, ' C ':} unvisited = {Node:none for node I N nodes} #把None作为无穷大使用 visited = {} #用来记录已经松弛过的数组 current = ' B ' #要找B点到其他点的距离 currentdistance = 0 Unvisited[current] = Curre Distance from ntdistance#b to B is recorded as 0 while True:for neighbour, distance in Distances[current].items (): If neighbour not in U Nvisited:continue# has been visited, jumping out of this cycle newdistance = currentdistance + distance# new distance if Unvisited[neighbour] is N One or Unvisited[neighbour] > newdistance: #如果两个点之间的距离之前是无穷大或者新距离小于原来的距离 unvisited[neighbour] = newdistance# Update distance Visited[current] = currentdistance# This point has been slack, record del unvisited[current] #从未访问过的字典中将这个点删除 if not unvisited:b
reak# if all the points are slack, jump out of this cycle Candidates = [node for node in Unvisited.items () if NODE[1]] #找出目前还有拿些点未松弛过 Current, currentdistance = sorted (candida
TES, key = Lambda x:x[1]) [0] #找出目前可以用来松弛的点
The first cycle of this code does not slack at any point, the primary purpose of the first cycle is to order the current distance to each point and find the next point for relaxation. The time complexity of this algorithm is only O (n^2). If you have the knowledge of the heap, you can also successfully reduce the time complexity of this algorithm to O (m+n) Logn. However, this algorithm is still not able to solve the negative rights of the graph, then we encounter with negative power of the map and what to do. Then we need Bellman-ford algorithm. Bellman-ford Algorithm
Bellman-ford algorithm can solve the problem of the shortest path with negative right, and what is the negative right. If the distance between the two vertices is positive, that distance becomes a positive right. Conversely, if the distance of a vertex to a vertex is negative, then this distance is called negative weight. Bellman-ford and Dijkstra are similar, using the ' relaxation ' method to find the shortest distance. Now, let's look at the Bellman-ford example.
Bellman-ford how to find the shortest distance from the s point to the other point.
Initial state:
The first relaxation we found that the S-point can reach the E and a points directly, then we can reach D,c via E and point A, and then we can get to B via C, and now update our table.
S: |
a:10 |
b:10 |
C:12 |
D:9 |
E:8 |
When all the points have been relaxed once, we have a second relaxation, in the second relaxation, I will be able to find D to AH a,c are negative, should be able to reduce the distance.
And then the second slack, and now we're going to do the third time slack.
Okay, now we're going to start relaxing for the fourth time, so we need to relax a few times. We need to reduce the number of vertices to relax, because in the figure, the shortest path of any two points contains at most n-1 edges, if after N-1 relaxation can continue to relax, it shows that this figure is a negative power loop diagram, there is no shortest path.
Fourth time Relaxation:
The fourth relaxation and third relaxation results have been, which means we have now found the other shortest paths from the s point to the graph.
Close the door. On the code.
g = {1:{1:0, 2:-3, 5:5}, 2:{2:0, 3:2}, 3:{3:0, 4:3}, 4:{4:0, 5:2}, 5:{5:0} def getedges (g):
"" Read in Figure G, return the list of edges and Endpoints "" "V1 = [] # starting point v2 = [] # corresponding adjacent arrival point w = [] # vertex v1 to the edge of vertex v2 For I in G:for J in G[i]: if G[I][J]!= 0:w.append (g[i][j)) v1.
Append (i) V2.append (j) return V1,v2,w def bellman_ford (g, V0, inf=999): V1,v2,w = Getedges (g) # initializes the shortest distance between the source point and all points dis = Dict ((k,inf) for K in G.keys ()) dis[v0] = 0 # core algorithm for K in range (len
(G)-1): # circular n-1 Wheel check = 0 # used to mark whether dis occurs in this round slack update for I in range (Len (w)): # A relaxation operation for each edge If Dis[v1[i]] + W[i] < Dis[v2[i]]: dis[v2[i]] = Dis[v1[i]] + w[i] Check = 1 if check = = 0:break # detect negative Loop # If the shortest path still changes after n-1 relaxation, the graph must have a negative-weight loop flag = 0 for I-Ra Nge (Len (w)): # Try a slack operation on each side again if Dis[v1[i]] + W[i] < Dis[v2[i]: Flag = 1 break if flag = = 1: # Raise Cycleerror () return False return dis v0 = 1 dis = Bellman_ford (G, v0) print Dis.valu ES ()
The time complexity of the Bellman-ford algorithm is O (MN), but we can still optimize the algorithm, in practice, we often find that the shortest path can be found without looping to N-1 times, so we can compare the two relaxation results, if two results are consistent, It can be explained that relaxation is done without further cycling. the difference between Bellman-ford and Dijkstra
Bellman-ford can be used in graphs that contain negative weights and Dijkstra are not available.
Why Dijkstra not. The reason for this is that, in Dijkstra, once a vertex is used for relaxation, its minimum value has been fixed and will not participate in the next relaxation. Because all the distance in the Dijkstra is a positive right, so it is impossible to a-b-C distance than the A-b-d-c of the short distance, and Bellman-ford in each cycle, will be each point to relax again, so can deal with negative rights.
Temporarily think of this difference, think of it again to add slightly, chirp ~