数塔(dp_基础)
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
有如上所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
已经告诉你了,这是个DP的题目,你能AC吗?
Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间0,990,99内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Sample Output
30
解题思路
- 很自然就可以想到暴力搜索的方法但是费时长,会超时
- 暴力搜索是从上向下搜索,那么继续考虑就会想到从下向上
- 把最下面的俩个数字找出最大的加到他上面的那个数
- 把最后一排执行完再依次执行上一行
具体思路如下
发表候看到图片看的不太清晰,各位可以放大观看,游览器一般按ctrl + +
初始状态
从下向上比较执行
那么可以看到在第二行第一个存储了左边那部分的较大值和
右边也一样
第二行的每个元素存储了他下面的的最优子结构
那么只需要比较出第二行的然后加到第一个元素,就是最大的情况了
代码如下
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;
int a[100][100]; // 用二维数组存储数据
int main()
{
int C;
scanf("%d",&C);
while (C--)
{
memset(a,0,sizeof(a)); //把数组初始化为0
int n; //数塔的高度
scanf("%d",&n);
for (int i = 0;i < n;i++)
{
for(int j = 0;j <= i;j++)
{
scanf("%d",&a[i][j]); //输入数塔
}
}
for (int i = n-1;i > 0;i--)
{
for(int j = 0;j <= i;j++)
{
a[i-1][j] += max(a[i][j],a[i][j+1]); //状态转移公式
}
}
printf("%d\n",a[0][0]);
}
return 0;
}
注意点
- 数组的下表从0开始所以要减一
- 所谓的最优子结构就如同该题的一个格子,这个格子一定是代表着他下面到他当前位置的和的最大值
- 重新画了一下图,希望帮到各位。
- 如果觉得我哪里写的不清楚,希望各位评论,指正,感激不尽。
- -