特别鸣谢:来自夸夸群的 醉笑陪公看落花@知乎,王不懂不懂@知乎,
感谢醉笑陪公看落花@知乎 倾囊相授,感谢小伙伴们督促学习,一起进步
相关文章:
文章目录
847. 访问所有节点的最短路径
存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号。
给你一个数组 graph 表示这个图。其中,graph[i] 是一个列表,由所有与节点 i 直接相连的节点组成。
返回能够访问所有节点的最短路径的长度。你可以在任一节点开始和停止,也可以多次重访节点,并且可以重用边。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-path-visiting-all-nodes
输入:graph = [[1,2,3],[0],[0],[0]]
输出:4
解释:一种可能的路径为 [1,0,2,0,3]
解法1 - 比特位状态+BFS+动态规划- 通过
class Solution:
def shortestPathLength(self, graph: List[List[int]]) -> int:
return solve1(graph)
import collections
def solve1(graph):
N = len(graph)
q = collections.deque([[1<<i,i] for i in range(N)])
dist = collections.defaultdict(lambda :N*N)
for i in range(N):dist[1<<i,i]=0
while q:
cover,i = q.popleft()
d = dist[cover,i]
if cover==2**N-1:return d
for c in graph[i]:
cover2 = cover | 1<<c
if d+1<dist[cover2,c]:
dist[cover2, c] = d+1
q.append([cover2,c])
方法2 - 比特位状态+DFS+动态规划 - 超时
class Solution:
def shortestPathLength(self, graph: List[List[int]]) -> int:
return solve2(graph)
'''
比特位状态+DFS+动态规划
'''
import collections
def solve2(graph):
N = len(graph)
dist = collections.defaultdict(lambda :N*N)
for i in range(N):dist[1<<i,i]=0
for i in range(N):
DFS(graph, dist, 1 << i, i)
distance = [dist[2**N-1, i] for i in range(N)]
return min(distance)
def DFS(graph,dist,cover,i):
N = len(graph)
if cover == 2 ** N - 1: return
d = dist[cover, i]
for c in graph[i]:
cover2 = cover | 1 << c
if d + 1 <= dist[cover2, c]:
dist[cover2, c] = d + 1
DFS(graph,dist,cover2, c)
小知识点
python
import collections
- 双端队列
q = collections.deque([[1<<i,i] for i in range(N)])
- 字典指定初始值
dist = collections.defaultdict(lambda :N*N)
比特位表示图的访问情况
1<<i
用比特位记录i
节点被访问这个事情
BFS vs DFS
- 当解空间离root较近的时候, 用BFS (相当于从多个出发点开始寻找)
- 当解空间离root较远的时候, 用DFS (相当于从一个出发点开始找,直到找到叶子结点,再从另一个出发点开始找)
本地的解空间离root较进,用BFS比较合适. 此外, 用DFS需要把所有路径找完了,再求一遍不同出发点得到的最小值. 而BFS 只需要找到第一个遍历到所有节点的路径,就是最小值了
时间复杂度比较 2log2(n) vs n
f(n) = 2log2(n) - n 的图像如下
n在 2~4之间的时候, 2log2(n) 大于n