题目描述:

上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 1。
输入描述
输入的第一行包含一个整数 N (1≤N≤100)N (1≤N≤100),表示三角形的行数。
下面的 NN 行给出数字三角形。数字三角形上的数都是 0 至 100 之间的整数。
输出描述
输出一个整数,表示答案。
输入输出样例
输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出
27
题目链接:
题目分析:【超级详细版】
首先确定实现的方式:
方式①:垂直往下走属于往左下走,往右下走就是往右下走【简化题干,代码实现更简单】
cpp
//7
//3 8
//8 1 0
//2 7 4 4
//4 5 2 6 5
方式②:往左下走,往右下走【完美贴合题意但是实现起来比较复杂】【逻辑和方式①一样,就是需要补很多0】
cpp
//000070000
//000308000
//008010000
//020704040
//405020605
我写的是方式①【越简单越好】
【做这个题难点的就是一句话:向左下走和右下走的次数不超过1】
cpp
我一开始有很多的想法,我在想是不是让我每走一步就得去判断向左走和向右走的差值【也就是左一
步+右一步,或者右一步+左一步的走】,感觉像是贪心的思想,每次考虑局部最优(大),最后就是总
和最大,但是无一例外的失败的,不是代码写出来无法通过样例,而是我根本就写不出来代码...
然后我转换了思路,一步一判断不好实现,那我就整体走完再判断符合题意的,这个能通过,而且经
过我多轮数据的检测,我发现了这个题条件:" 向左下走和右下走的次数不超过1 " 可以等价于先
一直往左(右)走,走到行数的中位数时候再往右(左)走,这个时候其实输出的位置是定死的,也就是
可以根据n的奇偶性直接锁定需要输出的位置【期间也看了大佬们的题解才发现】,于是我总结了这个
规律:
★向左下走【L】的次数与向右下走【R】的次数相差不能超过1,需要|L-R|<=1
★由于N行的数字三角形移动的次数是(N-1)次,所以
★当N为奇数时,移动(N-1)次,移动的次数是偶数,要想|L-R|<=1,当且仅当L=R时满足
★当N为偶数时,移动(N-1)次,移动的次数是奇数,要想|L-R|<=1,当且仅当L=R+1或者L=R-1时满足
可执行代码:
cpp
#include<bits/stdc++.h>
using namespace std;
long long n,ans;
const long long N=1000;
long long a[N][N],dp[N][N];
int main(){
cin>>n;
for(long long i=0;i<n;i++){
for(long long j=0;j<=i;j++){
cin>>a[i][j];
}
}
dp[0][0]=a[0][0];
for(long long i=1;i<n;i++){
for(long long j=0;j<=i;j++){
if(j==0){
dp[i][j]=dp[i-1][j]+a[i][j];
continue;
}
if(j==i){
dp[i][j]=dp[i-1][j-1]+a[i][j];
continue;
}
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j];
}
}
if(n%2==0){//n为偶数
long long ret1=n/2;
long long ret2=(n-1)/2;
ans=max(dp[n-1][ret1],dp[n-1][ret2]);
}else{//n为奇数
long long ret=(n-1)/2;
ans=dp[n-1][ret];
}
cout<<ans;
return 0;
}