847. 访问所有节点的最短路径
给出 graph 为有 N 个节点(编号为 0, 1, 2, …, N-1)的无向连通图。
graph.length = N,且只有节点 i 和 j 连通时,j != i 在列表 graph[i] 中恰好出现一次。
返回能够访问所有节点的最短路径的长度。你可以在任一节点开始和停止,也可以多次重访节点,并且可以重用边。
示例 1:
输入:[[1,2,3],[0],[0],[0]]
输出:4
解释:一个可能的路径为 [1,0,2,0,3]
示例 2:
输入:[[1],[0,2,4],[1,3,4],[2],[1,2]]
输出:4
解释:一个可能的路径为 [0,1,4,2,3]
提示:
1 <= graph.length <= 12
0 <= graph[i].length < graph.length
解答
采用广度优先搜索,记录当前已经访问的节点(最多只有12个节点,用12bit记录)。用队列实现广度优先搜索,判断当前的状态是否曾经访问过,如果曾经访问过就跳过。用一个list存放状态,大小为N*2^N。逐层访问。
# -*- coding: utf-8 -*-
from collections import deque, namedtuple
GraphNode = namedtuple('GraphNode',['id','nodes_visited'])
class Solution:
def shortestPathLength(self, graph):
"""
:type graph: List[List[int]]
:rtype: int
"""
# 采用广度优先搜索,记录当前已经访问的节点(最多只有12个节点,用12bit记录)
# 用队列实现广度优先搜索,判断当前的状态是否曾经访问过,如果曾经访问过就跳过
# 用一个list存放状态,大小为N*2^N
# 逐层访问
N = len(graph)
q = deque()
# 起始节点
for n in range(N):
q.append(GraphNode(n, 1<<n))
# 所有节点
all_nodes = 0
for i in range(N):
all_nodes = all_nodes | (1<<i)
# 记录已经访问过的状态
states_seen = [[ 0 for j in range(pow(2, N))] for i in range(N)]
# 当前已经访问的长度
path_length = 0
while q:
# 当前层的队列长度
nq = len(q)
while nq:
nq = nq - 1
cur_node = q.popleft()
# 判断是否已经访问了所有的节点
if cur_node.nodes_visited == all_nodes:
return path_length
# 邻接节点
neighbours = graph[cur_node.id]
for id in neighbours:
nodes_visited = cur_node.nodes_visited
# 添加已访问的节点
nodes_visited = nodes_visited | (1<<id)
# 判断当前的状态是否访问过,若有则跳过,若没有则添加到队列并且更新状态
if states_seen[id][nodes_visited]:
continue
states_seen[id][nodes_visited] = 1
q.append(GraphNode(id, nodes_visited))
path_length = path_length + 1
return -1