题意
输入一个三角形,从最顶层的数字开始向左下或向右下走,每条路径都加起来,问和最大的那条路径的和多少。
思路
这算是第二次接触DP,第一次是做leetcode的最长上升子序列问题。
DP在我看来有一点内存换时间
的意思 ,就是存储先前已经计算过的路径,然后在接下来的计算中使用。
在这里推荐一篇文章,我觉得把DP讲的非常好,链接:https://blog.csdn.net/baidu_28312631/article/details/47418773
代码
#include <stdio.h>
#define MAXN 10000 + 10
#define N 100 + 10
#define Max(x, y) (x > y ? x : y)
int cache[N][N];
int maxsum[MAXN];
int main() {
int R, i, j;
while(~scanf("%d", &R)) {
for(i = 1; i <= R; i++)
for(j = 1; j <= i; j++)
scanf("%d", &cache[i][j]);
for(i = 1; i <= R; i++)
maxsum[i] = cache[R][i];
for(i = R - 1; i >= 1; i--)
for(j = 1; j <= i; j++)
maxsum[j] = Max(maxsum[j], maxsum[j+1]) + cache[i][j];
printf("%d\n", maxsum[1]);
}
return 0;
}
上面用的是自顶向下的递推计算, 也可以用记忆化搜索的方法。
记忆化搜索其实是递归的一个改写,通过判断这个状态是否已经计算, 计算过直接返回, 没计算则加入递归进行计算,直接返回已经计算的值。
递归写法
int solve(int i, int j)
{
return a[i][j] + i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1));
}
这种写法很巧妙的定了边界n。
记忆化搜索
memset(dp, -1, sizeof(dp));
int solve(int i, int j) {
if (dp[i][j] >= 0) return dp[i][j];
return dp[i][j] = a[i][j] + (i == n ? max(solve(i + 1, j), solve(i + 1, j + 1)));
}