- 问题背景
- Dp分析
-
状态表示
- 二维状态表示
f(i,j) f(i,j)表示的是哪一个集合:所有满足如下条件的集合- 所有从起点出发,走到 (i, j) 的路径
f(i,j)存的是什么属性:Max,Min,数量;在这里f(i,j)存的应该是最大值,即路径上数字和的最大值 * 状态计算:f(i,j)可以怎么算出来?- 这里可以将集合分为两个子集
- 来自左上
- f(i, j) = f(i - 1, j - 1) + a(i, j)
- 来自右上
- f(i, j) = f(i - 1, j) + a(i, j)
- 来自左上
- 因此 f(i, j) = max( f(i - 1, j - 1), f(i - 1, j) ) + a(i, j)
- 二维状态表示
-
代码
-
f[1][1] = a[1][1]; for (int i = 2; i <= n; i++) { for (int j = 1; j <= n; j++) { f[i][j] = Math.max(f[i - 1][j - 1], f[i - 1][j]) + a[i][j]; } }
-
-
优化:将二维转换成一维
-
观察状态计算的过程,可以发现两个特点:
- f( i ) 层的计算只用到了f(i - 1) 层
- f( i ) 层中的 j 的计算只用到了**f(i - 1)**层中的 j 和 j - 1
-
因此可以做如下优化
- 将 i 这一维直接优化掉,i 的每一层循环中的 j 都在原先的 j 上进行覆盖
- j 的每一层循环中要注意 ,在计算 j 时要用到当前上一层 j和 j - 1 ,由于j - 1 < j,所以在这一层循环中要从后往前遍历,防止 j - 1 被提前更新
-
代码
-
f[1] = a[1][1]; for (int i = 2; i <= n; i++) { for (int j = n; j >= 1; j--) { f[j] = Math.max(f[j - 1], f[j]) + a[i][j]; } }
-
-
练习
- 题目
- 题解1
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 510;
public static final int INF = 0x3f3f3f3f;
public static int[][] a = new int[N][N];
public static int[][] f = new int[N][N];
public static int n;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
a[1][1] = Integer.parseInt(br.readLine());
//i表示层数
for (int i = 2; i <= n; i++) {
String[] str1 = br.readLine().split(" ");
for (int j = 1; j <= i; j++) {
a[i][j] = Integer.parseInt(str1[j - 1]);
}
}
//注意处理边界,自己模拟一下
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= n; j++) {
f[i][j] = -INF;
}
}
f[1][1] = a[1][1];
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= n; j++) {
f[i][j] = Math.max(f[i - 1][j - 1], f[i - 1][j]) + a[i][j];
}
}
int res = -INF;
for (int i = 1; i <= n; i++) {
res = Math.max(res, f[n][i]);
}
pw.println(res);
br.close();
pw.close();
}
}
- 题解2
import java.io.*;
import java.util.*;
public class Main {
public static final int N = 510;
public static final int INF = 0x3f3f3f3f;
public static int[][] a = new int[N][N];
public static int[] f = new int[N];
public static int[] g = new int[N];
public static int n;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
n = Integer.parseInt(br.readLine());
a[1][1] = Integer.parseInt(br.readLine());
//i表示层数
for (int i = 2; i <= n; i++) {
String[] str1 = br.readLine().split(" ");
for (int j = 1; j <= i; j++) {
a[i][j] = Integer.parseInt(str1[j - 1]);
}
}
//注意处理边界,自己模拟一下
for (int i = 0; i <= n; i++) {
f[i] = -INF;
}
f[1] = a[1][1];
for (int i = 2; i <= n; i++) {
for (int j = n; j >= 1; j--) {
f[j] = Math.max(f[j - 1], f[j]) + a[i][j];
}
}
int res = -INF;
for (int i = 1; i <= n; i++) {
res = Math.max(res, f[i]);
}
pw.println(res);
br.close();
pw.close();
}
}