问题描述
小U决定在一个 𝑚×𝑛 的地图上行走。地图中的每个位置都有一个高度,表示地形的高低。小U只能在满足以下条件的情况下移动:
- 只能上坡或者下坡,不能走到高度相同的点。
- 移动时必须交替进行:上坡后必须下坡,下坡后必须上坡,不能连续上坡或下坡。
- 每个位置只能经过一次,不能重复行走。
任务是帮助小U找到他在地图上可以移动的最大次数,即在符合所有条件的前提下,小U能走过的最大连续位置数量。
例如在以下2x2的地图中:
1 2
4 3
中庸行者可以选择移动顺序 3 -> 4 -> 1 -> 2,最大移动次数为3。
问题理解
-
地图行走规则:
- 小U只能在高度不同的位置之间移动。
- 移动时必须交替进行:上坡后必须下坡,下坡后必须上坡。
- 每个位置只能经过一次。
-
目标:
- 找到小U在地图上可以移动的最大次数,即在符合所有条件的前提下,小U能走过的最大连续位置数量。
数据结构选择
- 二维数组:用于表示地图,存储每个位置的高度。
- 访问标记数组:用于记录每个位置是否已经被访问过。
- 方向数组:用于表示上下左右四个方向的移动。
算法步骤
-
初始化:
- 创建一个二维数组
visited用于标记每个位置是否被访问过。 - 创建一个方向数组
directions用于表示上下左右四个方向的移动。
- 创建一个二维数组
-
深度优先搜索 (DFS):
- 从每个未访问的位置开始,进行深度优先搜索。
- 在DFS过程中,根据当前位置的高度和前一个位置的高度,决定下一步是上坡还是下坡。
- 记录每次DFS的最大深度(即最大移动次数)。
-
返回结果:
- 返回所有DFS结果中的最大值。
下面为我写的代码(java)
import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static int solution(int m, int n, int[][] a) {
int ans = 0;
int i, j;
int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
boolean[][] visited = new boolean[m][n];
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
ans = Math.max(ans, dfs(a, visited, directions, i, j, true, m, n));
ans = Math.max(ans, dfs(a, visited, directions, i, j, false, m, n));
}
}
return ans;
}
private static int dfs(int[][] a, boolean[][] visited, int[][] directions, int x, int y, boolean isUp, int m, int n) {
int ans1 = 0;
visited[x][y] = true;
for (int[] s : directions) {
int newx = x + s[0];
int newy = y + s[1];
if (newx >= 0 && newx < m && newy >= 0 && newy < n && !visited[newx][newy]) {
if (isUp && a[newx][newy] < a[x][y]) {
ans1 = Math.max(ans1, 1 + dfs(a, visited, directions, newx, newy, false, m, n));
} else if (!isUp && a[newx][newy] > a[x][y]) {
ans1 = Math.max(ans1, 1 + dfs(a, visited, directions, newx, newy, true, m, n));
}
}
}
visited[x][y] = false;
return ans1;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int m = scanner.nextInt(), n = scanner.nextInt();
int i, j;
int[][] a = new int[m][n];
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++)
a[i][j] = scanner.nextInt();
}
System.out.println(solution(m, n, a));
}
}
关键步骤
- visited:用来标记一下该点是否被搜索过
- isUp:用于判断对于该点之前的操作是上坡还是下坡
写在最后
这道题思路严谨,解题时需要严格规划好如何判断点位是否符合要求,以及想好dfs函数如何去实现搜索每一个点,需要考虑的地方很多,大家在完成此题的时候可以对dfs算法以及更高级的回溯算法有所了解。