题目:
描述
一个数字三角宝塔。
设数字三角形中的数字为绝对值不超过1000的整数。
现规定从最顶层走到最底层,每一步可沿向下或右斜线向下走。
求解从最顶层走到最底层的一条路径,使得沿着该路径所经过的数字的总和的绝对值最大,输出最大值
输入
输入数据的第1 行是数字三角形的行数n,1<=n<=1000。
接下来n行是数字三角形各行中的数字。所有数字都小于1000。
输出
程序运行结束时,将计算出的最大值输出。
样例
输入
4
1
3 2
4 10 1
4 3 2 20
输出
24
这道题只是数字三角形的升级版,在原题中加入了绝对值,如果再用原来的判断就会有问题,这道题主要就是来解决这个问题。
如普通的的数字三角形还没有弄懂请看这篇博客:网址
所以随即我们的第一反应就是给原来的代码在计算中加一个绝对值,细微处理一下即可。
如下面这篇代码:
#include <bits/stdc++.h>
using namespace std;
int n,a[110][110],dp[110][110],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
}
}
dp[1][1]=a[1][1];
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
if(abs(dp[i-1][j]+a[i][j])>abs(dp[i-1][j-1]+a[i][j])){
dp[i][j]=dp[i-1][j]+a[i][j];
}else{
dp[i][j]=dp[i-1][j-1]+a[i][j];
}
}
}
for(int i=1;i<=n;i++){
if(abs(dp[n][i])>abs(ans)){
ans=dp[n][i];
}
}
cout<<ans;
return 0;
}
但是,我们这样做为什么爆零了呢,因为这样的状态转移方程他的设定就是每次取绝对值最大的,但像下面这组数据就过不了
上一篇代码的答案就会是1,而这个数据答案显然是5。
于是,我们开始深入思考,上篇代码的问题出在只考虑绝对值大小,而没有关注这个数本身的大小,我们通过负数求最大绝对值就一直求最小值,我们通过正数求最大绝对值就一直求最大值,所以我们可以分别来算最大值和最小值,最后再来比较其绝对值大小。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[1100][1100],dp[3][1100][1100];//其实dp第一维大小只需要二,求最大值和最小值, 这里为了方便观看,用1和2来表示
int main() {
cin>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
cin>>a[i][j];
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
if(j==0||j>i)dp[1][i][j]=-1e5,dp[2][i][j]=1e5;
dp[1][1][1]=dp[2][1][1]=a[1][1];
for(int i=2; i<=n; i++)
for(int j=1; j<=i; j++)
dp[1][i][j]=a[i][j]+max(dp[1][i-1][j],dp[1][i-1][j-1]),
dp[2][i][j]=a[i][j]+min(dp[2][i-1][j],dp[2][i-1][j-1]);
int ans1=-1e9,ans2=1e9;
for(int i=1; i<=n; i++)
ans1=max(ans1,dp[1][n][i]),
ans2=min(ans2,dp[2][n][i]);
printf("%d\n",max(abs(ans1),abs(ans2)));
return 0;
}