前言
最近有点偷懒…T-T
一、题目
二、正常思路
从最后一层向上求dp[i][j](表示从第i层j列开始到最后一层最大数字和)
则dp两个来源,dp[i+1][j],dp[i+1][j+1];上代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int a[105][105];
int dp[105][105];
int main(){
memset(dp,0,sizeof(dp));
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
if(i==n){
dp[i][j]=a[i][j];//初始化最后一层dp
}
}
}
for(int i=n-1;i>=1;i--){
for(int j=1;j<=i;j++){
dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);
}
}
cout<<dp[1][1]<<endl;
}
三、考虑递推
这种情况和之前学到的dfs搜索技术差不多,都是暴力搜索所有可能情况,所以TLE
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int a[105][105];
int dp[105][105];
int n;
int dfs(int i,int j) {
if(i==n) {
return a[i][j];
}
return dp[i][j]=a[i][j]+max(dfs(i+1,j),dfs(i+1,j+1));
}
int main() {
memset(dp,0,sizeof(dp));
// int n;
cin>>n;
for(int i=1; i<=n; i++) {
for(int j=1; j<=i; j++) {
cin>>a[i][j];
if(i==n) {
dp[i][j]=a[i][j];
}
}
}
for(int i=n-1; i>=1; i--) {
for(int j=1; j<=i; j++) {
// dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);
dfs(i,j);
}
}
cout<<dp[1][1]<<endl;
}
四、加记忆化搜索剪枝
在前面暴力递推时不难发现,在进行递推时,有的d[i][j]我们算过不止一次
例如,想要算第二层3和8出发的递归时,都经过了第三行的1,所以这里可以记忆这点,进行剪枝,记住这是dp初始化为-1
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int a[105][105];
int dp[105][105];
int n;
int dfs(int i,int j) {
if(i==n) {
return a[i][j];
}
if(dp[i][j]>=0){
return dp[i][j];
}
return dp[i][j]=a[i][j]+max(dfs(i+1,j),dfs(i+1,j+1));
}
int main() {
memset(dp,-1,sizeof(dp));
// int n;
cin>>n;
for(int i=1; i<=n; i++) {
for(int j=1; j<=i; j++) {
cin>>a[i][j];
if(i==n) {
dp[i][j]=a[i][j];
}
}
}
for(int i=n-1; i>=1; i--) {
for(int j=1; j<=i; j++) {
// dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);
dfs(i,j);
}
}
cout<<dp[1][1]<<endl;
}