引言
题目是力扣的年赛题目,很经典的一道题。融合了很多基础的知识。尤其是涉及到了旅行商问题。
题目链接
一定要想清楚,旅行商问题和其他的dijkstra算法等路径算法的区别。旅行商问题是给定起点,途径全部点,回到终点的最短距离。思路是采用数位dp。
题目相对容易理解,我们需要明确一下思路。采用倒推答案,我们最后的目标是要求解找到一个最短路径,这个路径给定了终点和起点,要求途径全部的机关。因此其实是一个旅行商问题。需要用数位DP的方法。旅行商问题是给定了起点,求解途径全部中点的并回到起点的距离。我们这里给定起点,并且要求途径除了起点以外的全部点,最后在从最后一个机关点走到终点。
因此我们需要得到任意两个机关之间,起点/终点到任意机关的距离,这个距离需要途径任意一个石堆,因此我们可以在给定了两个机关的位置之后,枚举石堆,计算途径一个石堆的最短距离。这里我们考虑mindis[i][j]
表示机关i
和机关j
之间的最短距离,由于机关只有nb
个,因此mindis[i][nb], mindis[i][nb+1]
分别存储机关到起点,和机关到终点的距离。
我们还需要利用bfs,计算某个起点(机关),到任意一个点的距离。这样可以计算出机关到石堆的距离。
class Solution {
int[] dx = {
1, -1, 0, 0};
int[] dy = {
0, 0, 1, -1};
int n, m;
public int minimalSteps(String[] maze) {
n = maze.length;
m = maze[0].length();
// 机关 & 石头
List<int[]> buttons = new ArrayList<int[]>();
List<int[]> stones = new ArrayList<int[]>();
// 起点 & 终点
int sx = -1, sy = -1, tx = -1, ty = -1;
// 第一遍遍历地图
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (maze[i].charAt(j) == 'M') {
buttons.add(new int[]{
i, j});
}
if (maze[i].charAt(j) == 'O') {
stones.add(new int[]{
i, j});
}
if (maze[i].charAt(j) == 'S') {
sx = i;
sy = j;
}
if (maze[i].charAt(j) == 'T') {
tx = i;
ty = j;
}
}
}
int nb = buttons.size();
int ns = stones.size();
int[][] startDist = bfs(sx, sy, maze);
// 边界情况:没有机关
if (nb == 0) {
return startDist[tx][ty];
}
// 从某个机关到其他机关 / 起点与终点的最短距离。
int[][] dist = new int[nb][nb + 2];
for (int i = 0; i < nb; i++) {
Arrays.fill(dist[i], -1);
}
// 中间结果
int[][][] dd = new int[nb][][];
for (int i = 0; i < nb; i++) {
int[][] d = bfs(buttons.get(i)[0