数字三角形
- 题目:
有一个由非负整数组成的三角形,第一行只有一个数,除了最下行之外的每个数正下方和右下方各有一个数,只能往正下或者往右走一步,从上到下加起来最大的数是多少?
- 分析:
求最优的问题,考虑使用动态规划。动态规划可以用填表法可以更好理解其状态转移方程,一般可以维护两个表:value[][]表用以记录子问题的最优解,status[][]表用以记录状态(有些问题需要记录填表的路径)。这里使用a[i][j]存储这个数字三角形。使用F[i][j]记录value[][]。F[i][j]表示从[0][0]出发到达[i][j]所能得到的最大值。
- 状态转移方程:
F[i][j]=a[i][j]+max{F[i-1][j-1],F[i-1][j]}
- 解释:理解状态转移方程很重要。在求F[i][j]的时候,路径只能是从左上方或者正上方来,即依赖值F[i-1][j-1],F[i-1][j]。此时必然要求F[i-1][j-1]和F[i-1][j]是从(0,0)点到(i-1,j-1)和(i-1,j)所能获得的最大值。
- 用填表法模拟动态规划的过程:
- 对F表,先填容易填的,确定的作为对F表的初始化:
由于路径只能向下或向右,因此表中填好的数据没有别的选择,只能取如图数值。
- 对于剩下的3个未填空格,取F[2][1]作为例子。路径只能从F[1][0]或者F[1][1]来。显然4>3,因此我们选择F[1][0]。而F[1][0]已经是从(0,0)到(1,0)所能得到的最大值了。
剩下的填法一样。
- 代码示例:
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 100;
int a[maxn][maxn];
int value[maxn][maxn];
int status[maxn][maxn];
#define max(x,y) (x>y?x:y)
int main(){
int n;
while(cin>>n,n!=0){
memset(value,-1,sizeof(value));
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
cin>>a[i][j];
}
}
value[0][0] = a[0][0];
for(int i=1;i<n;i++){
for(int j=0;j<n;j++){
if(j==0) value[i][j] = value[i-1][j];
else{
value[i][j] = max(value[i-1][j-1],value[i-1][j]);
}
}
}
for(int i=1;i<n;i++){
cout<<endl;
for(int j=0;j<n;j++){
cout<<value[i][j];
}
}
}
}