题目:一个数字三角宝塔。
设数字三角形中的数字为绝对值不超过1000的整数
现规定从最顶层走到最底层,每一步可沿向下或向右下走。
求解从最顶层走到最底层的一条路径,使得沿着该路径所经过的数字的总和的绝对值最大,输出最大值。
Input
输入数据的第1 行是数字三角形的行数n,1<=n<=1000。
接下来n行是数字三角形各行中的数字。所有数字都小于1000。
Output
程序运行结束时,将计算出的最大值输出。
输入数据 1
4
1
3 2
4 10 1
4 3 2 20
输出数据 1
24
思路:
这类题目其实有两种方式:一种是考虑路径从上到下,另外一种是考虑路径从下到上,因为元素的值是不变的,所以路径的方向不同也不会影响最后求得的路径和。如果是从上到下,你会发现,在考虑下面元素的时候,起始元素的路径只会从[i - 1][j]
获得,且每行当中的最后一个元素的路径只会从 [i - 1][j - 1]
获得,中间二者都可,这样就需要处理边界问题,而且到了最后还需要判断最后一行各数的绝对值大小,比较麻烦。因此这里考虑从下到上的方式,状态的定义就变成了 “最后一行元素到当前元素的最大或最小路径和”,对于 [1][1]
这个元素来说,最后状态表示的就是我们的最终答案。
另外,由于题意要求总和的绝对值最大,所以我们需要用2个DP数组来分别计算最大值和最小值的情况,最后判断两个数组中dp[1][1]的绝对值大小就行。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int nums[1001][1001], dpMax[1001][1001], dpMin[1001][1001];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= i; ++j)
cin >> nums[i][j];
for (int i = 1; i <= n; ++i) { //最后一行赋值给两个DP数组
dpMax[n][i] = nums[n][i];
dpMin[n][i] = nums[n][i];
}
for (int i = n - 1; i >= 1; --i)
for (int j = 1; j <= i; j++) {
//当前最大值为下层两个数最大值与当前数的和
dpMax[i][j] = max(dpMax[i + 1][j], dpMax[i + 1][j + 1]) + nums[i][j];
//当前最小值为下层两个数最小值与当前数的和
dpMin[i][j] = min(dpMin[i + 1][j], dpMin[i + 1][j + 1]) + nums[i][j];
}
//输出绝对值最大值
cout << (abs(dpMax[1][1]) > abs(dpMin[1][1]) ? abs(dpMax[1][1]) : abs(dpMin[1][1]));
return 0;
}