https://www.bilibili.com/video/av36886554?t=538
https://blog.csdn.net/qq_35644234/article/details/60875818
floyd算法:能够找到图中任意两个节点之间的最短路径,时间复杂度为O(n**3),其中n表示图中的节点数
算法思路:
假设当前的
通过floyd算法计算图中任意两个节点之间的距离,需要构建两个矩阵:
distance_matrix shape=[num_node,num_node],其中的第i行第j列的元素表示从图中第i个节点到第j个节点的最短距离。
prior_matrix shape=[num_node,num_node],其中的第i行第j列的元素表示从图中第i个节点到第j个节点的最短距离的最短路径上,所经过的与起始节点(节点编号为i+1的节点)最近的中间节点。(这样就可以根据prior_matrix[i][j]的数值得到:如果需要找到最短路径,所需要经过的第一个中间节点是什么)
总共需要对于矩阵distance_matrix 和 prior_matrix 进行num_node 次更新:
'''
对输入的无向图,以及无向图中的节点和边
通过floyd算法求出图中任意两个节点之间的最短路径长度以及最短路径
输入的第一行表示:
无向图中的节点数num_node和边数num_vertice
假设无向图中的节点编号:1,2,…… num_node
后面的num_vertice行表示无向图中每条边的起始顶点,终止顶点和边的权重
输入:
7 12
1 2 12
1 6 16
1 7 14
2 3 10
2 6 7
3 4 3
3 5 5
3 6 6
4 5 4
5 6 2
5 7 8
6 7 9
'''
def find_path(prior_matrix,i,j):
'''
:param prior_matrix: 记录从所有初始节点到终止节点的最短路径所需要经过的上一个节点
:param i:当前的起始节点 i+1为真实节点编号
:param j:当前的终止节点 +1为真实节点编号
:return:返回最短路径所经过的节点
'''
if prior_matrix[i][j]==j:
return 'node%d'%(i+1)+'->'+'node%d'%(j+1)
else:
return find_path(prior_matrix,i,prior_matrix[i][j])+find_path(prior_matrix,prior_matrix[i][j],j)
if __name__=='__main__':
line1=list(map(int,input().split()))
num_node=line1[0]
num_vertice=line1[1]
vertice_list=[]
for i in range(num_vertice):
temp_line=list(map(int,input().split()))
vertice_list.append(temp_line)
distance_matrix=[[float('inf') for i in range(num_node)] for j in range(num_node)]
for i in range(num_node):
distance_matrix[i][i]=0
for vertice in vertice_list:
distance_matrix[vertice[0]-1][vertice[1]-1]=vertice[2]
distance_matrix[vertice[1] - 1][vertice[0] - 1] = vertice[2]
# 无向图的距离路径矩阵为对称矩阵
# print(distance_matrix)
prior_matrix=[[0 for i in range(num_node)] for j in range(num_node)]
# 初始化prior矩阵
for p in range(num_node):
for q in range(num_node):
prior_matrix[p][q]=q
# print(prior_matrix)
# 从for循环的角度也可以看出,floyd算法的时间复杂度是O(n**3)
for k in range(num_node):
# 将无向图中的当前节点加入进来,判断以当前节点为中介节点后,最短路径是否发生变换
for i in range(num_node):
for j in range(num_node):
if distance_matrix[i][j]>distance_matrix[i][k]+distance_matrix[k][j]:
# 更新距离矩阵中的数值
distance_matrix[i][j]=distance_matrix[i][k]+distance_matrix[k][j]
prior_matrix[i][j]=prior_matrix[i][k]
print('各个顶点对之间的最短路径:')
# print(prior_matrix)
# print(distance_matrix)
for i in range(num_node):
print('\n')
for j in range(i+1,num_node):
'''
prior_matrix
[[0, 1, 1, 5, 5, 5, 6],
[0, 1, 2, 2, 5, 5, 5],
[1, 1, 2, 3, 4, 5, 4],
[4, 2, 2, 3, 4, 4, 4],
[5, 5, 2, 3, 4, 5, 6],
[0, 1, 2, 4, 4, 5, 6],
[0, 5, 4, 4, 4, 5, 6]]
prior_matrix 矩阵中表示的数值是递归的含义
比如从节点1->节点4的最短路径
对应到prior_matrix 矩阵中是第0行第3列,即为5,
这表明:从节点1到节点4的最短路径等于从节点1到节点6的最短路径加上从节点6到节点4的最短路径
[1,4]
由于prior_matrix[0][3]=5!=3,说明从节点1到节点4的最短路径上包含中间节点5(节点编号6)
故而需要找到从1—->6和从6——>4分别的最短路径
从1——>6 由于 prior_matrix[0][5]=5!=5 说明从节点1到节点6的最短路径不包含中间节点了,输出路径1-->6
从6——>4 由于 prior_matrix[5][3]=4!=3 说明从节点6到节点4的最短路径包含中间节点4(节点编号5)
从6——>5 由于 prior_matrix[5][4]=4==4 说明从节点5到节点4的最短路径不包含中间节点了,输出路径6-->4
递归找到最短路径 1-->6 6-->4
'''
temp_route=[]
# prior=prior_matrix[i][j]
# print('here',prior,prior_matrix[i][prior])
temp_route=find_path(prior_matrix,i,j)
if temp_route.count('>')==1:#如果从初始节点i到终止节点j并不需要任何的中间节点,则直接输出字符串
display_line=temp_route
# print('\n')
# print()
# print(temp_route)
else:
# 此时 find_path 函数返回字符串具有中间的overlap,需要去重
# print(temp_route)
output_str=temp_route.split('->')
display_line=''
display_line+='node%d'%(i+1)
for t in range(1, len(output_str) - 1):
# output_str[t] = output_str[t][0:int(len(output_str) / 2)]
display_line+='->n'+output_str[t][0:int(len(output_str[t]) / 2)]
display_line += '->node%d' % (j + 1)
print('node%d->node%d: distance:%d' % (i + 1, j + 1, distance_matrix[i][j]), 'route:', display_line)
# print(display_line)
# a = '1->22->3535->5'
# b = a.split('->')
# print(b)
# for i in range(1, len(b) - 1):
# b[i] = b[i][0:int(len(b[i]) / 2)]
# print(b)
# ['1', '22', '3535', '5']
# ['1', '2', '35', '5']
# 下面这段根据prior_matrix寻找最短路径的代码是错误的,其错误根源在于没有对prior_matrix矩阵中的元素正确理解
# while prior_matrix[i][prior]!=prior:
# # print('in while')
# temp_route.append(prior)
# prior=prior_matrix[i][prior]
# temp_route.append(prior)
# temp_route = temp_route[::-1]
#
# if prior!=j:
# temp_route.append(j)
#
# temp_str='node%d'%(i+1)
# for elem in temp_route:
# temp_str+='->node%d'%(elem+1)
#
# print(temp_str)
终端输出信息:
D:\anaconda\envs\python36\python.exe "F:/1_实习/项目/medical image/my_code/6.py"
7 12
1 2 12
1 6 16
1 7 14
2 3 10
2 6 7
3 4 3
3 5 5
3 6 6
4 5 4
5 6 2
5 7 8
6 7 9
各个顶点对之间的最短路径:
node1->node2: distance:12 route: node1->node2
node1->node3: distance:22 route: node1->nnode2->node3
node1->node4: distance:22 route: node1->nnode6->nnode5->node4
node1->node5: distance:18 route: node1->nnode6->node5
node1->node6: distance:16 route: node1->node6
node1->node7: distance:14 route: node1->node7
node2->node3: distance:10 route: node2->node3
node2->node4: distance:13 route: node2->nnode3->node4
node2->node5: distance:9 route: node2->nnode6->node5
node2->node6: distance:7 route: node2->node6
node2->node7: distance:16 route: node2->nnode6->node7
node3->node4: distance:3 route: node3->node4
node3->node5: distance:5 route: node3->node5
node3->node6: distance:6 route: node3->node6
node3->node7: distance:13 route: node3->nnode5->node7
node4->node5: distance:4 route: node4->node5
node4->node6: distance:6 route: node4->nnode5->node6
node4->node7: distance:12 route: node4->nnode5->node7
node5->node6: distance:2 route: node5->node6
node5->node7: distance:8 route: node5->node7
node6->node7: distance:9 route: node6->node7
Process finished with exit code 0