有如下所示的数塔,要求从底层走到顶层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
输入:数据首先包括一个整数整数 N (1≤N≤100),表示数塔的高度,接下来用 N 行数字表示数塔,其中第 i 行有个i 个整数,且所有的整数均在区间[0,99] 内。
输出:从底层走到顶层经过的数字的最大和是多少?
解法一:DFS搜索(由于是全遍历+递归重复调用,时间较慢)
#include <bits/stdc++.h>
using namespace std;
int n , a[107][107] ,maxn;
void dfs(int x , int y , int sum){
maxn = max(sum , maxn);
if(x+1 <= n){
dfs(x+1,y,sum+a[x+1][y]);
dfs(x+1,y+1,sum+a[x+1][y+1]);
}
}
int main(){
scanf("%d" , &n);
for ( int i = 1 ; i <= n ; i++ )
for ( int j = 1 ; j <= i ; j++ )
scanf("%d" , &a[i][j]);
dfs(1,1,a[1][1]);
printf("%d" , maxn);
return 0;
}
解法二:递推写法的DP(运行时间快,消耗资源小)
#include <bits/stdc++.h>
using namespace std;
int n , a[107][107] , dp[107][107];
void d(){
for ( int i = 1 ; i <= n ; i++ )
dp[n][i] = a[n][i];
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]);
}
int main(){
scanf("%d" , &n);
for ( int i = 1 ; i <= n ; i++ )
for ( int j = 1 ; j <= i ; j++ )
scanf("%d" , &a[i][j]);
d();
printf("%d" , dp[1][1]);
return 0;
}
解法三:递归写法的DP(由于重复调用,效率不如递推的)
#include <bits/stdc++.h>
using namespace std;
int n , a[107][107] , dp[107][107];
int d(int x , int y){
if(x != n)
return a[x][y] + max( d(x+1 , y) , d(x+1 , y+1));
else
return a[x][y];
}
int main(){
scanf("%d" , &n);
for ( int i = 1 ; i <= n ; i++ )
for ( int j = 1 ; j <= i ; j++ )
scanf("%d" , &a[i][j]);
printf("%d" , d(1,1));
return 0;
}
解法四:记忆化搜索(将递归重复的部分去掉了)
#include <bits/stdc++.h>
using namespace std;
int n , a[107][107] , dp[107][107];
int d(int x , int y){
if(dp[x][y] != -1) return dp[x][y];
else if(x != n){
dp[x][y] = a[x][y] + max( d(x+1 , y) , d(x+1 , y+1));
return dp[x][y];
}
else
return a[x][y];
}
int main(){
memset(dp , -1 , sizeof(dp));
scanf("%d" , &n);
for ( int i = 1 ; i <= n ; i++ )
for ( int j = 1 ; j <= i ; j++ )
scanf("%d" , &a[i][j]);
printf("%d" , d(1,1));
return 0;
}