constint maxn = 10000; int graph[maxn][maxn]; //有向图的邻接矩阵 int dis[maxn]; //记录某个点到起点的最短距离 int path[maxn]; //记录前驱节点 int vis[maxn]; //记录某个点是否被更新过 int n, m, s; //点数
voiddijkstra(int s) { memset(path, -1, sizeof(path)); memset(dis, 0x3f, sizeof(dis)); //初始化为无穷大 /*INF使用0x3f3f3f3f的好处: * 1:满足无穷大加一个有穷的数依然是无穷大(在DijKstra算法松弛操作中避免了溢出而出现负数) * 2:满足无穷大加无穷大依然是无穷大(两个0x3f3f3f3f相加结果为0x7e7e7e7e,并未溢出) * 3:初始化时,由于每一个字节为0x3f,所以只需要memset(buf,0x3f,sizeof(buf))即可(memset是以字节为单位初始化的) */ memset(vis, 0, sizeof(vis)); //初始化所有节点都没有永久标签 dis[s] = 0; //起点自己到自己的距离为0 while (1) { int point = 0; for (int i = 1; i <= n; i++) //寻找临时标签中到起点距离最小的点 { if (!vis[i] && dis[i] < dis[point]) point = i; } if (!point) //如果没找到,则返回 return; vis[point] = 1; //把找到的这个点更新为永久标签 for (int i = 1; i <= n; i++) { //如果原最短距离比现距离大(现距离即为刚刚找到的点到起点的最短距离+该点到邻接点的距离),则更新 //如果某点无法通过该永久标签点到达,则加上的是一个无穷大,则仍为原距离 if (dis[i] > dis[point] + graph[point][i]) { dis[i] = dis[point] + graph[point][i]; //更新最短距离 path[i] = point; //路径被改变,重新记录前驱 } } } }
intmain() { cin >> n >> m >> s; memset(graph, 0x3f, sizeof(graph)); for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; graph[u][v] = w; } dijkstra(s); for (int i = 1; i <= n; i++) cout << dis[i] << " "; cout << endl; print(4); return0; }
Python实现:
n, m, s = map(int, input().split()) dis = [float("inf")]*(n+1) # 记录某个点到起点的最短距离,初始化为无穷大 path = [-1]*(n+1) # 记录前驱节点,初始化为-1 vis = [False]*(n+1) # 记录某个点是否被更新过,初始都未被更新
defprintPath(x): # 输出路径,x为终点 if x == -1: return printPath(path[x]) # 小递归 if x != s: print("->", end="") print(x, end="")
# 构造邻接矩阵 graph = [[float("inf") for i inrange(n+1)] for j inrange(n+1)] for i inrange(m): src, des, w = map(int, input().split()) graph[src][des] = w
# 起点自己到自己的距离为0 dis[s] = 0
whileTrue: point = 0
# 寻找临时标签中到起点距离最小的点 for i inrange(1, n+1): if (not vis[i]) and dis[i] < dis[point]: point = i
# 如果没找到,则退出循环 if point == 0: break
# 把找到的这个点更新为永久标签 vis[point] = True
# 如果原最短距离比现距离大(现距离即为刚刚找到的点到起点的最短距离+该点到邻接点的距离),则更新 # 如果某点无法通过该永久标签点到达,则加上的是一个无穷大,则仍为原距离 for i inrange(1, n+1): if dis[i] > dis[point]+graph[point][i]: dis[i] = dis[point]+graph[point][i] path[i] = point
constint maxn = 10001; constint maxm = 500001; int n, m, s; int vis[maxn], dis[maxn], path[maxn], head[maxn]; //vis记录某个点是否被更新过,dis记录某个点到起点的最短距离,path记录前驱节点,head[i]记录以第i个点为起点的所有边所构成的链表的首下标
structEdge { //u,v,w,next:起点,终点,权值,下一条边的序号 int u, v, w, next; } edge[maxm];
def__lt__(self, other): if self.dis < other.dis: returnTrue else: returnFalse
defprintPath(x): # 输出路径,x为终点 if x == -1: return printPath(path[x]) # 小递归 if x != s: print("->", end="") print(x, end="")
# 链式前向星,用C++实现起来较为复杂,Python的字典可以轻松实现这一功能 # 以每条边的起点为键,以同起点的所有边的终点和权所组成的字典为值,建立链表 graph = {i: {} for i inrange(1, n+1)} for i inrange(m): src, des, w = map(eval, input().split()) graph.get(src)[des] = w
whilelen(myheap) > 0: # 取出首节点 x = heappop(myheap) index = x.index if vis[index]: continue vis[index] = True # 搜索以堆顶节点为起点的所有连边 for des, w in graph.get(index).items(): if dis[des] > dis[index]+w: dis[des] = dis[index]+w path[des] = index # 把新遍历到的点加入堆中 heappush(myheap, Point(des, dis[des]))