python 無向圖最短路徑之floyd算法

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章