目录
题目:
给出 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]
示例什么意思呢?
每一个维度的数据表示第i个节点可到的其他节点,如[[1],[0,2,4],[1,3,4],[2],[1,2]]表示:节点0可以到节点1,节点1可以到0,2,4;节点2可以到1,3,4;节点3可以到2;节点4可以到1,2
思路:BFS
class State {
int cover, head;
State(int c, int h) {
cover = c;
head = h;
}
}
cover 表示当前已经访问过的所有节点
head 表示当前节点
如何用cover当前已经访问过的所有节点?
状态压缩
每个节点的“未遍历”与“已遍历”可以用0/1表示
如果 cover 的第 k 个比特位是 1,表示该路径经过了第 k 个节点
定义一个二维数组dist
dist[i][j],i对应 State里的cover,j对应 State里的head
i和j两个变量一起表示了一种状态,能够表示已经遍历了哪些节点
dist[i][j]里面存放的则是:在目前这种状态下的最短路径
N个结点,一共2N种状态,所以数组要有2N行
代码:int[][] dist = new int[1<<N][N];
BFS需要用到队列:Queue queue = new LinkedList();
//结点入队并对dist数组做初始化
for (int[] row: dist) Arrays.fill(row, N*N);
for (int x = 0; x < N; ++x) {
queue.offer(new State(1<<x, x));
dist[1 << x][x] = 0;
}
BFS过程
while (!queue.isEmpty()) {
State node = queue.poll(); //从队列中取出一个状态State
int d = dist[node.cover][node.head]; //取出当前状态下的最短路径
if (node.cover == (1<<N) - 1) return d; //如果当前的State中的cover化成二进制后全是1,也就是说已经遍历完所有节点了,返回当前状态下的最短路径
for (int child: graph[node.head]) { //遍历当前节点的邻接点
int cover2 = node.cover | (1 << child); //如果能找到一条新路径
if (d + 1 < dist[cover2][child]) { //并且相同状态下,当前路径的长度,比之前找到的路径还短(相同状态下可能不止一条路径,dist存放同一状态路径最短值)
dist[cover2][child] = d + 1; //更新dist[i][j]的值
queue.offer(new State(cover2, child));//新路径所表示的状态State入队
}
}
}
整体代码
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, N*N);
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;
}
}