之前学了弗洛依达(Floyd)算法,类似于暴力搜索,但在有的算法题中可能会出现超时的状况。因此又去学了迪杰斯特拉算法。下边是我对这个算法所做的总结。包括初次尝试的失败案例。
简介:
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。
算法思想:
迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
例题:
题目链接:用户登录https://www.lanqiao.cn/problems/1122/learning/?page=1&first_category_id=1&second_category_id=8
1.题目描述:
蓝桥王国一共有N个建筑和M条单向道路,每条道路都连接着两个建筑,每个建筑都有自己的编号,分别为1~N。(其中皇宫编号为1)
国王想让小明回答从皇宫到每个建筑的最短距离是多少,但紧张的小明此时已经无法思考,请你编写程序帮助小明回答国王的考核。
2.输入描述:
输入第一行包含两个正整数N,M。
第2到M+1行每行包含三个正整数u,v,w,表示u->v之间存在一条距离为w的路。
3.输出描述:
输出仅一行,共N个数,分别表示从皇宫到编号为1~N建筑的最短距离,两两之间用空格隔开。(如果无法到达输出为-1)
举个简单例子:
1->2距离初始化为1
1->3距离初始化为5
2->3距离初始化为2
在实现的过程中,尽可能的找到一个中间点,尝试“绕路”寻找最短路径。比如1->3距离是5,但是我可以绕路,先从1走到2距离是1,再从2走到3,距离为2,更新1->3的距离,为3,比之前的5要小。
4.原始算法
import os
import sys
n,m=map(int,input().split())
ds=[[0x3f for j in range(n+1)] for i in range(n+1)]#ds存储点之间的距离
for i in range(1,m+1):
u,v,w=map(int,input().split())
ds[u][v]=min(ds[u][v],w)
d=[0x3f for i in range(n+1)]#d存储从节点1到节点n之间的距离
d[1]=0#节点1到自身的距离为0
st=[False for i in range(n+1)]#st标记节点是否使用过
for i in range(1,n+1):
temp=-1
for j in range(1,n+1):
if not st[j] and(temp==-1 or d[j]<d[temp]):#寻找一个距离短的中间节点j
temp=j
st[temp]=True#标记节点使用过
for i in range(1,n+1):
d[i]=min(d[i],d[temp]+ds[temp][i])#更新节点间的距离
for i in range(1,n+1):
print(f'{d[i]}',end=' ')
在提交的时候发现运行超时。
5.算法优化
import heapq
INF=float("inf")#INF表示无穷大
N,M=map(int,input().split())
dp[INF]*(N+1)#dp存储节点1到节点i的距离
a=[[] for _ in range(N+1)]#存储节点之间的距离
for i in range(1,M+1):
u,v,w=map(int,input().split())
a[u].append((v,w))
q=[]
heapq.heappush(q,(0,1))#(0,1)0表示距离,1表示节点,队列会自动按照第一维的值排序,所以距离0放在前边
dp[1]=0#表示节点1到自身距离为0
def dij():
vis=[0 for i in range(N+1)]#标记节点是否用过
while q:
v=heapq.heappop(q)[1]
if vis[v]==1:continue
vis[v]=1
for vnext,wnext in a[v]:
if vsi[vnext]==1:continue
vis[vnext]=1
dp[vnext]=min(dp[vnext],dp[v]+wnext)
heapq.heappush(q,(dp[vnext],vnext))
dij()
for i in range(N+1):
if dp[i]==INF:
print(-1,end=' ')
else:
print(dp[i],end=' ')