看了九章算法的动态规划专题课,记录一下。
动态规划可以解什么题
- 计数
- 有多少种方式走到右下角
- 有多少种方式选出K个数使得和为sum
- 求最大值或最小值
- 从左上角走到右下角路径的最大数字和
- 最长上升子序列长度
- 求存在性
- 取石子游戏,先手是否必胜
- 能不能选出K个数使得和为sum
基本思路
- 确定状态
- 从最后一步出发
- 化解为子问题
- 确定转移方程
- 可以根据子问题定义直接得出
- 考虑初始条件和边界情况
- 确定计算顺序
- 需要利用到之前计算的结果
常见动态规划类型
- 坐标型动态规划
- 序列型动态规划
- 划分型动态规划
- 区间型动态规划
- 背包型动态规划
- 最长序列型动态规划
- 博弈型动态规划
- 综合型动态规划
例 落谷P1216
https://www.luogu.com.cn/problem/P1216
- 确定状态
这是一道最值型dp题,要求出从最高点到底部路径最大数字和f[x][y],那么必须先求出从最高点到倒数第二行路径最大数字和f[x-1][y-1]或者f[x-1][y],取二者最大值 - 转移方程
根据1分析,得状态转移方程f[x][y] = max(f[x][y]+f[x-1][y-1],f[x][y]+f[x-1][y]) - 初始条件和边界
可以考虑开一个[r+1][r+1]的数组,边界值为0。 - 计算循序
因为要利用到上一行的结果,所以考虑从上到下从左到右的计算顺序
public class P1216 {
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
int r = (int)in.nval;
int ans=0;
int[][] f = new int[r+1][r+1];
for(int i=1;i<=r;i++){
for(int j=1;j<=i;j++){
in.nextToken(); f[i][j] = (int)in.nval;
f[i][j] = Math.max(f[i][j]+f[i-1][j-1], f[i][j]+f[i-1][j]);
}
}
for(int i=1;i<=r;i++){
ans = Math.max(ans, f[r][i]);
}
System.out.println(ans);
}
}