原题描述
访问所有节点的最短路径。原题为在一张图中,有n个节点,编号为从0到n-1,这个图本身是一个无向连通图,要求一条路径,经过所有节点。注意,每一个节点和每一条边都可以被访问多次。值得关注的一点是图中节点数量不超过12。这个应该是解题的一个关键,不超过12意味着可以用状态压缩来保存当前的节点访问状态,即用12个bit,从低到高,分别表示节点0到节点n-1的访问状态,节点对应位为1,则表示该节点已被访问。
广度优先搜索
思路简述
很容易想到的一种做法就是广度优先搜索,求最短路径什么的,如果图各个边的权重是完全相同的,就可以使用广度优先搜索。广度优先搜索,可以使用双端队列来实现。在本题中,搜索的状态为当前访问的节点和历史访问状态(状态压缩)以及当前访问路径的长度。在实现上,需要用一个哈希表记录已经搜索过的状态,避免重复搜索。
代码
func shortestPathLength(graph [][]int) int {
n := len(graph)
deque := list.New()
visited := make(map[string]struct{
}, 0)
// 加入以各个点开始的初始状态
for i := 0; i < n; i++ {
deque.PushBack([]int{
i, 1 << i, 0}) // 初始状态
visited[fmt.Sprintf("%d-%d", i, 1 << i)] = struct{
}{
}
}
for deque.Len() != 0 {
cur := deque.Remove(deque.Front()).([]int)
curPos, state, pathLen := cur[0], cur[1], cur[2]
if state == (1 << n) - 1 {
// 状态压缩,此时相当于每一个点都被访问了
return pathLen // bfs, 所以可以直接返回答案
}
// 访问当前节点的所有邻居节点
for _, adj := range graph[curPos] {
newState := state | (1 << adj)
if _, ok := visited[fmt.Sprintf("%d-%d", adj, newState)]; ok {
continue
}
deque.PushBack([]int{
adj, newState, pathLen + 1})
visited[fmt.Sprintf("%d-%d", adj, newState)] = struct{
}{
}
}
}
return -1
}
复杂度分析
- 时间复杂度: O ( n 2 ∗ 2 n ) O(n^2* 2^n) O(n2∗2n),由于有哈希表保证在广度优先搜索中不会重复搜索,而状态数一共是 n ∗ 2 n n * 2 ^n n

最低0.47元/天 解锁文章
6937

被折叠的 条评论
为什么被折叠?



