python 无向图最短路径之floyd算法

85 篇文章 0 订阅

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

 

要找到python无向图中的最短路径,可以使用Dijkstra算法Floyd算法。 Dijkstra算法用于找到从一个顶点到其他所有顶点的最短路径。它通过逐步确定从起始顶点到其他顶点的最短距离,并记录最短路径的前驱顶点。这个算法的时间复杂度为O(num_node**2),其中num_node是中顶点的数量。 Floyd算法则可以找到中任意两个顶点之间的最短路径。它通过动态规划的方式,逐步更新两个顶点之间的最短路径长度。这个算法的时间复杂度为O(num_node**3)。 选择使用哪个算法取决于具体的需求。如果只需要找到从一个顶点到其他所有顶点的最短路径,可以使用Dijkstra算法。如果需要找到任意两个顶点之间的最短路径,可以使用Floyd算法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Python _系列之基于链接表>实现无向图最短路径搜索](https://blog.csdn.net/y6123236/article/details/123971104)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [python 无向图最短路径之Dijkstra算法](https://blog.csdn.net/WYXHAHAHA123/article/details/89678253)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值