题目
思路与代码
一.先将问题往适合DP的方向抽象。
1.将当前位置(i,j)看成一个状态,定义状态(i,j)的指标函数 d(i,j)为从位置(i,j)出发能得到的最大和(包括(i,j))。
2.原问题的解:d(1,1)。
3.状态之间是如何转换的,即状态转移方程:
4.本问题具有最优子结构的性质, 具体说明。
二.计算状态转移方程的方式
1.直接递归计算:
int solve(int i, int j) {
return G[i][j] + (i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1)));
}
优点:直接反映状态转移方程,思路明显。
缺点:进行了重复计算(重叠子问题),时间效率低。
复杂度:
(在此理解一下,重叠子问题的概念)
2.递推:
int i, j;
// 先处理最后一层结点
for (j = 1; j <= n; j++) d[n][j] = G[n][j];
// 依次逆着枚举出每个结点的决策
for (i = n - 1; i >= 1; i--)
for (j = 1; j <= i; j++)
d[i][j] = G[i][j] + max(d[i + 1][j], d[i + 1][j + 1]);
内容:逆着枚举出所有节点的决策。
在多数情况下,递推法的时间复杂度是:状态总数 x 每个状态决策个数 x 决策时间。
优点:快一些
缺点:需要自己找到结点的决策顺序。
复杂度:
3.记忆化搜索
int solve(int i, int j) {
if (d[i][j] >= 0) return d[i][j];
return d[i][j] = G[i][j] + (i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1)));
}
内容:递归的时候,顺便记忆一下。。。
优点:快一些,不需要自己找到结点的决策顺序
缺点:需要调用系统栈,所以比递推慢
复杂度:
码农小技巧
对于memset进行批量赋值时,只能用-1和0,1、-2、…会乱码。