【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;
}