一、前言
很早之前就想把之前看过的算法问题总结出来,现在出的书籍基本上都是以C、Java为基础的算法书籍,以Python为基础的算法书籍很少。自己最近在学ML,开始使用Python,相比较与C与Java,Python的代码量更少,代码阅读起来也比较简单,所以打算用Python将以前看过的算法总结一次。这个系列不以难易程度递增更新,想起哪个算法就先更新哪一个。
在图论中有一个很重要的问题--最短路径问题,最短路径应用方面很广,最早接触这个问题的是因为研究生期间要写一篇关于SDN路径规划论文,需要计算出业务流量在任意两点间传输的最短路径,当时选择了Floyd算法与Dijkstra算法。这次先更新Floyd算法,Dijkstra算法在之后的文章中会写。
二、算法基本介绍
如下图所示,图中点到点的路径都是单向的,单项箭头线上的数字表示点与点之间的距离。那么任意两点之间的最短路径应该怎么求呢?
首先,我们用一个矩阵来存储上图的信息。上图有四个点,因此我们使用一个4*4的矩阵来存储。
我们使用d[i][j]来表示任意两点之间的距离,那么上图中d[1][2]=2。d[2][1]为正无穷,则表示点2到点1在不经过第三个点的情况下为不可达。假设一下,如果AB两点之间的距离是固定的,那么我们怎么让这两点之间的距离变短,这时我们会想到引入第三个点C,有人可能会想,再多引入一个点怎么会让距离变的更短,注意,我们这里描述的两点之间的距离并不是直线距离。如下图所示d[A][B]>d[A][C]+d[C][B]。
假设现在只允许经过1号顶点,求任意两点之间的最短距离。如果d[i][1]+d[1][j]<d[i][j],则d[i][j]=d[i][1]+d[1][j]。因此最短路径更新如下,依次类推只允许经过2号顶点。
最后Python的实现代码如下:
for k in range(N):
for i in range(N):
for j in range(N):
if d[i][j] > d[i][k] + d[k][j]:
d[i][j] = d[i][k] + d[k][j]
三、算法基本应用
#/usr/bin/env python
#coding:utf-8
#editor:evan
#time:2018.03.14
import numpy as np
N = 4
M = 100
edge = np.mat([[0,2,6,4],[M,0,3,M],[7,M,0,1],[5,M,12,0]])
A = edge[:]
path = np.zeros((N,N))
def Floyd():
for i in range(N):
for j in range(N):
if(edge[i,j] != M and edge[i,j] != 0):
path[i][j] = i
print 'init:'
print A,'\n',path
for a in range(N):
for b in range(N):
for c in range(N):
if(A[b,a]+A[a,c]<A[b,c]):
A[b,c] = A[b,a] + A[a,c]
path[b][c] = path[a][c]
print 'result:'
print A,'\n',path
if __name__ == "__main__":
Floyd()
运行结果如下:
init:
[[ 0 2 6 4]
[100 0 3 100]
[ 7 100 0 1]
[ 5 100 12 0]]
[[ 0. 0. 0. 0.]
[ 0. 0. 1. 0.]
[ 2. 0. 0. 2.]
[ 3. 0. 3. 0.]]
result:
[[ 0 2 5 4]
[ 9 0 3 4]
[ 6 8 0 1]
[ 5 7 10 0]]
[[ 0. 0. 1. 0.]
[ 3. 0. 1. 2.]
[ 3. 0. 0. 2.]
[ 3. 0. 1. 0.]]