代码仓库:Github | Leetcode solutions @doubleZ0108 from Peking University.
(node, cost) 元组基础上还要加加一个traveled数组记录每个点当前是否被遍历。
改进1(T5% S85%):这么做超时的主要问题是因为traveled是数组,没法hash,因此无法使用visited记录(node, traveled)是否出现过减小搜索空间。解决办法是将这个数组变为字符串 → 更进一步可以变为二进制字符串 → 又可以用一位十进制数表示,这样既可以hash,又进行了状态压缩。具体来说,
如果十进制数 ==
2
N
−
1
2^N - 1
2N−1则代表所有节点都被访问到了,具体实现if traveled == (1 << N) - 1:
初始化为出发节点的二进制对应的十进制,1<
记录traveled信息的增加,traveled_ = traveled | (1 << dst)

改进2(T18% S33%):也可以把所有点作为起点都压入同一个队列中然后一起做(替代外层循环),只要找到一个traveled全覆盖的就可以终止返回了
class Solution(object):
def shortestPathLength(self, graph):
"""
:type graph: List[List[int]]
:rtype: int
"""
# 解法1 改进1
minCost = 1e06
for start in range(len(graph)): # 分别把每个点作为起始
queue = [(start, 0, 1<<start)]
visited = set((start, 1<<start))
while queue:
src, cost, traveled = queue.pop(0)
if traveled == (1 << len(graph)) - 1:
minCost = min(minCost, cost)
break
for dst in graph[src]:
traveled_ = traveled | (1 << dst)
if (dst, traveled_) not in visited:
queue.append((dst, cost+1, traveled_))
visited.add((dst, traveled_))
return minCost
def otherSolution(self, graph):
# 解法1 改进2
queue = [(start, 0, 1<<start) for start in range(len(graph))]
visited = set((start, 1<<start) for start in range(len(graph)))
while queue:
src, cost, traveled = queue.pop(0)
if traveled == (1 << len(graph)) - 1:
return cost
for dst in graph[src]:
traveled_ = traveled | (1 << dst)
if (dst, traveled_) not in visited:
queue.append((dst, cost+1, traveled_))
visited.add((dst, traveled_))
# 解法1(超时)
minCost = 1e06
for start in range(len(graph)): # 分别把每个点作为起始
queue = [(start, 0, [0 for _ in range(len(graph))])]
queue[0][-1][start] = 1
while queue:
src, cost, traveled = queue.pop(0)
if 0 not in traveled:
minCost = min(minCost, cost)
break
for dst in graph[src]:
traveled_ = traveled.copy()
traveled_[dst] = 1
queue.append((dst, cost+1, traveled_))
return