动态规划解决数塔问题

有如下所示的数塔,要求从底层走到顶层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

 输入:数据首先包括一个整数整数 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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值