python 图(最短路径)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37973607/article/details/86636447

       在一个有向图G=(V,E)中,G中每一条边都有一个比例常数W(Weight)与之对应,如果想求G图中某一个顶点V0到其他顶点的最少W总和的值,这类问题就称为最短路径问题。一般讨论的方向有两种:

  • 单点对全部顶点
  • 所有顶点对两两之间的最短距离

一、单点对全部顶点

       一个顶点到多个顶点的最短路径通常用Dijkstra算法求得。Dijkstra算法(迪杰斯特拉)是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。可以用堆优化。

# 图为邻接表形式
# Dijkstra算法——通过边实现松弛
# 指定一个点到其他各顶点的路径——单源最短路径
# 初始化图参数
G = {1:{1:0,2:1,3:12},
     2:{2:0,3:9,4:3},
     3:{3:0,5:5},
     4:{3:4,4:0,5:13,6:15},
     5:{5:0,6:4},
     6:{6:0}}

def Dijkstra(G,v0,INF=999): 
    """ 使用 Dijkstra 算法计算指定点 v0 到图 G 中任意点的最短路径的距离
        INF 为设定的无限远距离值
        此方法不能解决负权值边的图
    """
	book = set()
	minv = v0   # 源顶点到其余各顶点的初始路程
	dis = dict((k,INF) for k in G.keys())
	dis[v0] = 0 
	while len(book)<len(G):
		book.add(minv)                                  # 确定当期顶点的距离
		for w in G[minv]:                               # 以当前点的中心向外扩散
			if dis[minv] + G[minv][w] < dis[w]:         # 如果从当前点扩展到某一点的距离小与已知最短距离      
				dis[w] = dis[minv] + G[minv][w]         # 对已知距离进行更新
		new =INF                                       # 从剩下的未确定点中选择最小距离点作为新的扩散点
		for v in dis.keys():
			if v in book: continue
			if dis[v] < new: 
				new = dis[v]
				minv = v
	return dis
dis = Dijkstra(G,v0=1)
print(dis)

输出:{1: 0, 2: 1, 3: 8, 4: 4, 5: 13, 6: 17}

#图为邻接矩阵形式
NUMBER=6
INF=999
SIZE=7
Graph_Matrix=[[0]*SIZE for row in range(SIZE)]
def BuildGraph_Matrix(Path_Cost):
	for i in range(1,SIZE):
		for j in range(1,SIZE):
			if i==j:
				Graph_Matrix[i][j]=0
			else:
				Graph_Matrix[i][j]=INF
	i=0
	while i<len(Path_Cost):
		Start_Point=Path_Cost[i][0]
		End_Point=Path_Cost[i][1]
		Graph_Matrix[Start_Point][End_Point]=Path_Cost[i][2]
		i+=1
def Dijkstra(v0,vertex_total,INF=999): 
	book = set()
	minv = v0   # 源顶点到其余各顶点的初始路程
	dis = dict((k,INF) for k in range(1,vertex_total+1))
	dis[v0] = 0 
	while len(book)<vertex_total:
		book.add(minv)                                  # 确定当期顶点的距离
		for w in range(1,vertex_total+1):                               # 以当前点的中心向外扩散
			if dis[minv] +Graph_Matrix[minv][w] < dis[w]:         # 如果从当前点扩展到某一点的距离小与已知最短距离      
				dis[w] = dis[minv] + Graph_Matrix[minv][w]         # 对已知距离进行更新
		new =INF                                       # 从剩下的未确定点中选择最小距离点作为新的扩散点
		for v in dis.keys():
			if v in book: continue
			if dis[v] < new: 
				new = dis[v]
				minv = v
	return dis		
Path_Cost=[[1,2,1],[1,3,12],[2,3,9],[2,4,3],[3,5,5],[4,3,4],[4,5,13],[4,6,15],[5,6,4]]
BuildGraph_Matrix(Path_Cost)
print(Dijkstra(1,NUMBER))

二、两两顶点间的最短路径

       Dijkstra算法只能求出某一点到其他顶点的最短距离,如果要求出图中任意两点甚至所有顶点间最短的距离,就必须使用Floyd算法。Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(n^3),空间复杂度为O(n^2)。

      从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。

#有向图
SIZE=7
NUMBER=6
INF=999
Graph_Matrix=[[0]*SIZE for row in range(SIZE)]
distance=[[0]*SIZE for row in range(SIZE)]
def BuildGraph_Matrix(Path_Cost):
	for i in range(1,SIZE):
		for j in range(1,SIZE):
			if i==j:
				Graph_Matrix[i][j]=0
			else:
				Graph_Matrix[i][j]=INF
	i=0
	while i<len(Path_Cost):
		Start_Point=Path_Cost[i][0]
		End_Point=Path_Cost[i][1]
		Graph_Matrix[Start_Point][End_Point]=Path_Cost[i][2]
		i+=1
def Floyd(vertex_total,INF=999): 
    #初始化图的长度数组
	for i in range(1,vertex_total+1):
		for j in range(1,vertex_total+1):
			distance[i][j]=Graph_Matrix[i][j]
    #使用Floyd算法找出所有顶点两两之间的最短距离
	for k in range(1,vertex_total+1):
		for i in range(1,vertex_total+1):
			for j in range(1,vertex_total+1):
				if distance[i][k]+distance[k][j]<distance[i][j]:
					distance[i][j]=distance[i][k]+distance[k][j]
Path_Cost=[[1,2,20],[2,3,30],[2,4,25],[3,5,28],[4,5,32],[4,6,95],[5,6,67]]
BuildGraph_Matrix(Path_Cost)
Floyd(NUMBER)
for i in range(1,NUMBER+1):
	for j in range(1,NUMBER+1):
		print(distance[i][j],end=' ')
	print()

 输出:

0 20 50 45 77 140 
999 0 30 25 57 120 
999 999 0 999 28 95 
999 999 999 0 32 95 
999 999 999 999 0 67 
999 999 999 999 999 0 

#无向图(只需更改初始化图的长度数组部分代表)
for i in range(1,vertex_total+1):
		for j in range(i,vertex_total+1):
			distance[i][j]=Graph_Matrix[i][j]
			distance[j][i]=Graph_Matrix[i][j]

输出:

0 20 50 45 77 140 
20 0 30 25 57 120 
50 30 0 55 28 95 
45 25 55 0 32 95 
77 57 28 32 0 67 
140 120 95 95 67 0 
 

猜你喜欢

转载自blog.csdn.net/m0_37973607/article/details/86636447