可重复经过点和路径的覆盖问题
算法概论第十一周
847. Shortest Path Visiting All Nodes —— 题目链接
题目描述
An undirected, connected graph of N nodes (labeled 0, 1, 2, ..., N-1) is given as graph.
graph.length = N, and j != i is in the list graph[i] exactly once, if and only if nodes i and j are connected.
Return the length of the shortest path that visits every node. You may start and stop at any node, you may revisit nodes multiple times, and you may reuse edges.
Example 1:
Input: [[1,2,3],[0],[0],[0]]
Output: 4
Explanation: One possible path is [1,0,2,0,3]
Example 2:
Input: [[1],[0,2,4],[1,3,4],[2],[1,2]]
Output: 4
Explanation: One possible path is [0,1,4,2,3]
Note:
1 <= graph.length <= 12
0 <= graph[i].length < graph.length
思路分析
状态定义
- 由于路径可以重复使用,而且目标是把所有点经过一遍,于是可以尝试搜索所有的状态
- 每一个状态 S t a t e State State可以定义为 S t a t e = { C o v e r , C u r r } State = \{Cover,Curr\} State={Cover,Curr}, C o v e r Cover Cover 表示当前状态已经经过了哪些节点,可以使用状态压缩表示, C u r r Curr Curr表示当前在哪个节点
- 有两种搜索状态的方法
BFS
- 初始化一个记录二位数组
dist[状态总数][节点总数]
,用于记录每个状态的最短路径,初始化为无限大 - 一开始加入所有节点分别的初始出发状态进入队列
- 开始不断从队列取出状态
- 如果状态为覆盖所有点,返回距离
- 否则根据当前节点,查看所有与当前节点连接的点,尝试转移到这些点
- 如果转移的结果能缩短该状态的最短路径,将该状态加入队列
- 由于是BFS,可以保证找到最优解
实现代码
class Solution {
public int shortestPathLength(int[][] graph) {
int N = graph.length;
Queue<State> queue = new LinkedList();
int[][] dist = new int[1<<N][N];
for (int[] row: dist) Arrays.fill(row, 1000000000);
for (int x = 0; x < N; ++x) {
queue.offer(new State(1<<x, x));
dist[1 << x][x] = 0;
}
while (!queue.isEmpty()) {
State node = queue.poll();
int d = dist[node.cover][node.head];
if (node.cover == (1<<N) - 1) return d;
for (int child: graph[node.head]) {
int cover2 = node.cover | (1 << child);
if (d + 1 < dist[cover2][child]) {
dist[cover2][child] = d + 1;
queue.offer(new State(cover2, child));
}
}
}
throw null;
}
}
class State {
int cover, head;
State(int c, int h) {
cover = c;
head = h;
}
}