记忆化搜索
滑雪
- 问题背景
- Dp分析
-
状态表示
- 二维状态表示
f(i,j) f(i,j)表示的是哪一个集合:所有满足如下条件的集合- 所有从
f(i,j)开始滑的路径
- 所有从
f(i,j)存的是什么属性:Max,Min,数量;在这里f(i,j)存的应该是Max,即从f(i,j)开始滑,可以划过路径的最大值
- 二维状态表示
-
状态计算:
f(i,j)可以怎么算出来?- 分成四个子集
- 向上滑
- f(i, j) = f(i - 1, j) + 1
- 向右滑
- f(i, j) = f(i, j + 1) + 1
- 向下滑
- f(i, j) = f(i + 1, j) + 1
- 向左滑
- f(i, j) = f(i, j - 1) + 1
- 这里将向四个方向滑后的坐标记为 (a, b)
- (a, b) 需要满足 a >= 1 && a <= n && b >= 1 && b <= m && g(a, b) < g(i, j)
- 向上滑
- 分成四个子集
-
代码
-
public static int dp(int x, int y) { //如果f[x][y]已经被算出来了,直接返回 if (f[x][y] != -1) { return f[x][y]; } //如果f[i][j]没有被算过,赋初值1 f[x][y] = 1; //遍历四个方向 for (int i = 0; i < 4; i++) { int a = x + dx[i]; int b = y + dy[i]; if (a >= 1 && a <= n && b >= 1 && b <= m && g[x][y] > g[a][b]) { f[x][y] = Math.max(f[x][y], dp(a, b) + 1); } } return f[x][y]; }
-
练习
01 滑雪
- 题目
- 题解
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 310;
public static int[][] g = new int[N][N];
//从f(i,j)开始滑,可以划过路径的最大值
public static int[][] f = new int[N][N];
public static int[] dx = new int[]{-1, 0, 1, 0};
public static int[] dy = new int[]{0, 1, 0, -1};
public static int n, m;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
String[] str1 = br.readLine().split(" ");
n = Integer.parseInt(str1[0]);
m = Integer.parseInt(str1[1]);
for (int i = 1; i <= n; i++) {
String[] str2 = br.readLine().split(" ");
for (int j = 1; j <= m; j++) {
g[i][j] = Integer.parseInt(str2[j - 1]);
}
}
//初始化
for (int i = 1; i <= n; i++) {
Arrays.fill(f[i], 1, m + 1, -1);
}
int res = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
//这里是dp(i, j)而不是f[i][j]是因为f[i][j]还没有算出来
//f[i][j]是在dp(i, j)中才被算出来的
res = Math.max(res, dp(i, j));
}
}
pw.println(res);
pw.close();
br.close();
}
public static int dp(int x, int y) {
//如果f[x][y]已经被算出来了,直接返回
if (f[x][y] != -1) {
return f[x][y];
}
//如果f[i][j]没有被算过,赋初值1
f[x][y] = 1;
//遍历四个方向
for (int i = 0; i < 4; i++) {
int a = x + dx[i];
int b = y + dy[i];
if (a >= 1 && a <= n && b >= 1 && b <= m && g[x][y] > g[a][b]) {
f[x][y] = Math.max(f[x][y], dp(a, b) + 1);
}
}
return f[x][y];
}
}