- 【题目描述】
观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。
- 【输入】
第一个行包含R(1≤ R≤1000),表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
所有的被供应的整数是非负的且不大于100。
- 【输出】
单独的一行,包含那个可能得到的最大的和。
- 【输入样例】
5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11
- 【输出样例】
86
分析:
- 分析状态,找状态转移方程、边界条件
金字塔数字:(先全部初始化为0)
二维数组ary[][]
j i | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 13 | 0 | 0 | 0 | 0 |
2 | 0 | 11 | 8 | 0 | 0 | 0 |
3 | 0 | 12 | 7 | 26 | 0 | 0 |
4 | 0 | 6 | 14 | 15 | 8 | 0 |
5 | 0 | 12 | 7 | 13 | 24 | 11 |
搞个 二维数组 dp[][] dp[i][j]用来代表 第 i 层 j 列 数字出发的到达最顶端的最大和 (注:此表述未必正确)
首先:dp[1][1] 肯定是 ary[1][1] 即为边界条件
对于 dp[2][1] 我们可以得到 dp[2][1] = dp[1][0] + ary[2][1] 或者 dp[2][1] = dp[1][1] + ary[2][1] 中取最大值 即:dp[2][1] = max( dp[1][0] , dp[1][1] ) + ary[2][1]
同理 dp[2][2] = max( dp[1][1] , dp[1][2] ) + ary[2][2]
因此,我们可以草率的得到 dp[i][j] = max( dp[i-1][j-1] , dp[i-1][j] ) + ary[i][j] 即为状态转移方程
dp 数组最终结果
0 0 | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 13 | 0 | 0 | 0 | 0 |
2 | 0 | 24 | 21 | 0 | 0 | 0 |
3 | 0 | 36 | 31 | 47 | 0 | 0 |
4 | 0 | 42 | 50 | 62 | 55 | 0 |
5 | 0 | 54 | 57 | 75 | 86 | 66 |
C++程序:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int main(int argc, char** argv) {
int n;
scanf("%d",&n);
int ary[n+1][n+1];
int dp[n+1][n+1];
//数组初始化为0
memset(ary,0,sizeof(ary));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++)
scanf("%d",&ary[i][j]);
}
for(int i=0;i<=n;i++){
for(int j=0;j<=i;j++)
printf("%d ",ary[i][j]);
printf("\n");
}
//边界
dp[1][1] = ary[1][1];
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++)
//状态转移方程
dp[i][j] = max(dp[i-1][j-1],dp[i-1][j]) + ary[i][j];
}
//输出dp数组
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++)
printf("%d ",dp[i][j]);
printf("\n");
}
//输出最大和
int maxn = -1;
for(int i=1;i<=n;i++)
{
maxn=max(maxn,dp[n][i]);
}
printf("%d\n",maxn);
return 0;
}
注意:memset函数 需引进 cstring头文件
动态规划总结(截取 自 《算法笔记》(胡凡 曾磊 主编)