题目:
给你一个有 n
个节点的 有向带权 图,节点编号为 0
到 n - 1
。图中的初始边用数组 edges
表示,其中 edges[i] = [fromi, toi, edgeCosti]
表示从 fromi
到 toi
有一条代价为 edgeCosti
的边。
请你实现一个 Graph
类:
Graph(int n, int[][] edges)
初始化图有n
个节点,并输入初始边。addEdge(int[] edge)
向边集中添加一条边,其中edge = [from, to, edgeCost]
。数据保证添加这条边之前对应的两个节点之间没有有向边。int shortestPath(int node1, int node2)
返回从节点node1
到node2
的路径 最小 代价。如果路径不存在,返回-1
。一条路径的代价是路径中所有边代价之和。
思考:
初始化图和向图中添加边都很好解决,用邻接列表表示图即可。
shortestPath
方法是求一个节点到另一个节点的路径最小代价,很容易联想到迪杰斯特拉算法(确定一个起点,求得这个起点到所有节点的最短路径):
1. 数组s记录已求出最短路径的顶点,数组u记录还未求出最短路径的顶点,数组dis记录起点到所有节点的最短路径。初始时,s=(起点),u=(除起点外所有节点),dis中起点对应的值为0,其他节点对应的值为∞。
2. 遍历s中的点:当前访问的s中的点设为i,访问邻接列表中s相邻的所有点x,若dis[i]+相邻边代价<dis[x],即 起点到点i的最短距离+i到x的边的距离<当前起点到点x的最短距离,则更新dis[x]。
3. 更新完一轮dis[x]后(点i相邻的点x全部判断完了),取u中对应dis最小的点放入s中,继续进行步骤2,直至s中全部点都访问过了或u已经空了。
4. 最后返回dis[node2],若值为无穷大则返回-1.
代码如下:
class Graph(object):
def __init__(self, n, edges):
"""
:type n: int
:type edges: List[List[int]]
"""
self.n = n
self.graph = [[] for _ in range(0, n)] # 初始化邻接列表
for from_i, to_i, cost in edges:
self.graph[from_i].append((to_i, cost)) # 将每个边加入邻接列表
def addEdge(self, edge):
"""
:type edge: List[int]
:rtype: None
"""
self.graph[edge[0]].append((edge[1], edge[2]))
def shortestPath(self, node1, node2):
"""
:type node1: int
:type node2: int
:rtype: int
"""
# Dijkstra
# 数组S记录已求出最短路径的顶点
# 数组U记录还未求出最短路径的顶点
n = self.n
s = [node1]
u = [node for node in range(0, n) if node != node1]
# 数组dis表示起点到各个点的最短路径
dis = [float ('inf')] * (n)
dis[node1] = 0
i = 0
while True:
# 若s中所有点都被判断过了或者u为空,退出循环
if i >= len(s) or not u:
break
for x, y in self.graph[s[i]]: # 访问当前点的邻接点x
if y+dis[s[i]] < dis[x]:
dis[x] = y+dis[s[i]] # 更新起点到点x的最短路径
# 取出u中dis最短的点,加入s
idx = u[0]
for x in u:
if dis[x] < dis[idx]:
idx = x
s.append(idx)
u.remove(idx)
i += 1 # 开始下一轮循环
return dis[node2] if dis[node2] != float ('inf') else -1
提交通过: