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

100 篇文章 0 订阅
85 篇文章 0 订阅

 无向图:

在数据结构中的无向图通常使用邻接矩阵表示

无向图的邻接矩阵是对称矩阵,有向图的邻接矩阵不是对称矩阵。

共有5个顶点(nodes),7条边(vertices)

其邻接矩阵为:num_node*num_node,矩阵中的数值表示两个相连接的节点的边的权值

节点ABCDE
A06inf1inf
B60522
Cinf50inf5
D12inf01
Einf2510

在无向图中寻找最短路径通常使用的是Dijkstra算法和Floyd算法。

Dijkstra算法:给定某个特定的起始顶点,找到从起始顶点到图中所有顶点的距离最小值(最短路径),其时间复杂度为O(num_node**2)。

Floyd算法:找到从图中的所有顶点到达任意顶点的最短路径,其时间复杂度为O(num_node**3)。

一、Dijkstra算法

 

Dijkstra算法:其时间复杂度为O(n**2),其中n表示图中的节点个数

Dijkstra算法是基于两个列表的,分别是visited和unvisited

当前无向图中具有5个顶点。

假设是要找到从A到达所有节点最短的距离

第一次循环

在distance列表中找到所有unvisited列表中的节点所具有的最小distance值,发现是A距离最小(实际上就是初始节点/start node)

current_node=A

找到A在无向图中的邻居节点,发现是B,D。正好B,D都在unvisited列表中

distance[B]=min(distance(B),distance(A)+vertice(A,B))=min(float('inf'),0+6) =6  故更新distance列表中B的值

distance[D]=min(distance(D),distance(A)+vertice(A,D))=min(float('inf'),0+2)=1  故更新distance列表中D的值

将节点A从unvisted列表中删除,放到visited列表中

此时

visited=[A]

unvisited=[B,C,D,E]

distance[A,B,C,D,E]=[0,6,float(''inf),1,float(''inf)]

第二次循环

在distance列表中找到所有unvisited列表中的节点所具有的最小distance值,此时unvisted中是BCDE,则发现是D距离=1最小

current_node=D

找到D在无向图中的邻居节点,发现是A,B,E。A不在unvisited列表中,B,E在unvisited列表中。故不管A,只判断B,E

distance[B]=min(distance(B),distance(D)+vertice(D,B))=min(6,1+2) =3  故更新distance列表中B的值

distance[E]=min(distance(E),distance(D)+vertice(D,E))=min(float('inf'),1+1) =2  故更新distance列表中E的值

将节点D从unvisted列表中删除,放到visited列表中

此时

visited=[A,D]

unvisited=[B,C,E]

distance[A,B,C,D,E]=[0,3,float(''inf),1,2]

第三次循环

在distance列表中找到所有unvisited列表中的节点所具有的最小distance值,此时unvisted中是BCE,则发现是E距离=2最小

current_node=E

找到E在无向图中的邻居节点,发现是B,C,D。D不在unvisited列表中,B,C在unvisited列表中。故不管D,只判断B,C

distance[B]=min(distance(B),distance(E)+vertice(E,B))=min(3,2+2) =3  故不更新distance列表中B的值

distance[C]=min(distance(C),distance(E)+vertice(E,C))=min(float(''inf),2+5) =7  故更新distance列表中C的值

将节点E从unvisted列表中删除,放到visited列表中

此时

visited=[A,D,E]

unvisited=[B,C]

distance[A,B,C,D,E]=[0,3,7,1,2]

第四次循环

在distance列表中找到所有unvisited列表中的节点所具有的最小distance值,此时unvisted中是BC,则发现是B距离=4最小

current_node=B

找到E在无向图中的邻居节点,发现是A,C,D。A,D不在unvisited列表中,C在unvisited列表中。故不管A,D,只判断C

distance[C]=min(distance(C),distance(B)+vertice(B,C))=min(7,4+5) =7  故不更新 distance列表中C的值

将节点B从unvisted列表中删除,放到visited列表中

此时

visited=[A,D,E,B]

unvisited=[C]

distance[A,B,C,D,E]=[0,3,7,1,2]

第五次循环

在distance列表中找到所有unvisited列表中的节点所具有的最小distance值,此时unvisted中是C,则发现是C距离=7最小

current_node=C

找到E在无向图中的邻居节点,发现是B,E。B,E不在unvisited列表中,故不对任何节点的距离进行判断

将节点C从unvisted列表中删除,放到visited列表中

此时

 

visited=[A,D,E,B,C]

unvisited=[]

distance[A,B,C,D,E]=[0,3,7,1,2]

所输出的distance列表表示的就是:从起始节点A出发,到达无向图中每个节点的最短路径长度。

'''
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,
要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入描述:
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。
最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)

输出描述:
输出 一行有两个数, 最短距离及其花费。

输入
3 2
1 2 5 6
2 3 4 5
1 3
0 0
输出
9 11

您的代码已保存
运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为90.91%

感谢
https://www.bilibili.com/video/av38254646  讲的真的非常清楚

'''

if __name__=='__main__':
    line1=list(map(int,input().split()))
    num_node=line1[0]
    num_vertice=line1[1]

    no_direct_graph=[]

    for i in range(num_vertice):
        no_direct_graph.append(list(map(int,input().split())))

    start_end=list(map(int,input().split()))

    dict_graph={}
    for k in range(len(no_direct_graph)):#对于无向图中的每一条边
        for j in range(num_node):
            if no_direct_graph[k][0]==j+1:
                if j+1 not in dict_graph:
                    dict_graph[j+1]=[no_direct_graph[k]]
                else:
                    dict_graph[j + 1].append(no_direct_graph[k])
            elif no_direct_graph[k][1]==j+1:
                if j + 1 not in dict_graph:
                    dict_graph[j + 1] = [[no_direct_graph[k][1],no_direct_graph[k][0],no_direct_graph[k][2],no_direct_graph[k][3]]]
                else:
                    dict_graph[j + 1].append([no_direct_graph[k][1],no_direct_graph[k][0],no_direct_graph[k][2],no_direct_graph[k][3]])
    # print(dict_graph)   以字典的形式构造无向图

    visited=[]
    unvisited=[_+1 for _ in range(num_node)]

    distance=[float('inf') for _ in range(num_node)]

    money=[0 for _ in range(num_node)]

    temp=start_end[0]
    # money[temp - 1] = 0
    distance[temp-1]=0
    for j in range(num_node):
        temp_neighbor = dict_graph[temp]
        for route in temp_neighbor:
            # print('route',route)
            if route[1] not in visited:  # 如果当前节点的邻居节点没有被访问过
                if distance[temp - 1] + route[2]<distance[route[1] - 1]:
                    distance[route[1] - 1]=distance[temp - 1] + route[2]
                    # print(route[-1])
                    money[route[1] - 1]=money[temp-1]+route[-1]
                elif distance[temp - 1] + route[2]==distance[route[1] - 1]:#如果距离相等,取花费少的路径
                    if money[temp-1]+route[-1]<money[route[1] - 1]:
                        distance[route[1] - 1]=distance[temp - 1] + route[2]
                        money[route[1] - 1] = money[temp - 1] + route[-1]
        # 找到money数组中除了当前temp的money值之外剩下的所有元素中最小money数量的位置,作为下一个temp位置
        distance_compare = distance.copy()
        distance_compare[temp - 1] = float("inf")

        visited.append(temp)
        if temp in unvisited:
            unvisited.remove(temp)

        min_value = float("inf")
        min_index = 0

        for k in range(num_node):
            if k+1 in unvisited:#如果当前的节点并没有被访问过
                if distance_compare[k] < min_value:
                    min_value = distance_compare[k]
                    min_index = k
        temp = min_index + 1

    print(distance[start_end[-1]-1],money[start_end[-1]-1])

    # min_distance=min(distance)
    # min_money=[]
    # for i,q in enumerate(distance):
    #     if q==min_distance:
    #         min_money.append(money[i])
    # print(min_distance,min(min_money))

 

  • 6
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值