【SSL】1100 数字金字塔(DP)

【SSL】1100 数字金字塔(DP)

Time Limit:10000MS
Memory Limit:65536K

Description

在下面被显示的数字金字塔。写一个程序来计算从最高点开始在底部任意处结束的路径经过数字的和的最大。每一步可以走到左下方的点也可以到达右下方的点。
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
在上面的样例中,从7 到 3 到 8 到 7 到 5 的路径产生了最大和:30

Input

第一个行包含 R(1<= R<=1000) ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
所有的被供应的整数是非负的且不大于100。

Output

单独的一行包含那个可能得到的最大的和。

Sample Input

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

Sample Output

30

思路

看到这道题,我们会先想到把每种路线枚举一次,时间复杂度 O(2^n)。当R>26时,会超时。我们也可以用记忆化搜索,记忆化搜索的本质就是动态规划。可以用逆推的方法做,从上到下推可以压缩空间,用一维数组。也可以从下到上推。每一个位置都可以从左下方的点和右下方的点或左上方的点和右上方的点得到,可以推出状态转移方程为:f[x][y]=max(f[x+1][y],f[x+1][y+1])+a[x][y];当x=r时,f[x][y]=a[x][y],1<=x<=r,1<=y<=r。

代码

记忆化搜索

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int a[1010][1010],b[1010][1010];
int n,i,j,ans;
void input()//输入数据
{
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		for(j=1;j<=i;j++)
			scanf("%d",&a[i][j]);
	return;
}
int f(int x,int y)//记忆化搜索
{
	if (b[x][y]!=0)//判断是否记忆
		return b[x][y];
	if (x==n)//边界条件
		b[x][y]=a[n][y];
	else
		b[x][y]=max(f(x+1,y),f(x+1,y+1))+a[x][y];//状态转移方程
	return b[x][y];//返回结果
}
int main()
{
	input();
	printf("%d",f(1,1));//调用函数,计算结果
	return 0;
}

从上到下逆推

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int a[1010][1010],b[1010];
int n,i,j,ans;
void input()//输入数据
{
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		for(j=1;j<=i;j++)
			scanf("%d",&a[i][j]);
	return;
}
void work()
{
	b[1]=a[1][1];
	for(i=2;i<=n;i++)//从第2行往后推
	  for(j=i;j>=1;j--)//计算到走到当前位置可得到的最大值,从后往前可覆盖以前的结果,不影响计算
	    b[j]=max(b[j-1],b[j])+a[i][j];//状态转移方程
	ans=0;
	for(i=1;i<=n;i++)//在最后一行中找最大值为答案
		ans=max(ans,b[i]);
	return;
}
int main()
{
 	input();
	work();//计算结果
	printf("%d",ans);//输出结果
	return 0;
}

从下到上逆推

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int a[1010][1010],b[1010][1010];
int n,i,j,ans;
void input()//输入数据
{
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		for(j=1;j<=i;j++)
			scanf("%d",&a[i][j]);
	return;
}
void work()
{
	for(i=1;i<=n;i++)//最后一行赋初值
		b[n][i]=a[n][i];
	for(i=n-1;i>=1;i--)//从后往前推
		for(j=1;j<=i;j++)//计算到当前位置可得到的最大值
			b[i][j]=max(b[i+1][j+1],b[i+1][j])+a[i][j];//状态转移方程
	return;
}
int main()
{
	input();
	work();//计算结果
	printf("%d",b[1][1]);//输出结果
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值