numtri解题报告 —— icedream61 博客园(转载请注明出处)
------------------------------------------------------------------------------------------------------------------------------------------------
【题目】
有一个数字的金字塔,形状如下
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
要从顶端开始走,每次只能向左下或者右下走,求所经过的数字之和最大值。
【数据范围】
1<=R<=1000
0<=每个数<=100
【输入样例】
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
【输出样例】
30
------------------------------------------------------------------------------------------------------------------------------------------------
【分析】
DP。
设num[i][j]为i行j列的数,d[i][j]是从1行1列走到i行j列的当前最优解。
d[1][1]=num[1][1];
d[i][j]=0; // i>1 or j>1
从1行1列走到R行某列的最大值,可以直接递归出来,状态转移方程如下:
当i==1,j>=2时,d[i][j]=d[i-1][j]+num[i][j];
当i>=2,j>=2时,d[i][j]=max{d[i-1][j]+num[i][j],d[i-1][j-1]+num[i][j]};
但本题,递归有边界情况,比较麻烦,递推更方便,状态转移方程如下:
当i>=2,2<=j<R时
d[i+1][j]=max{d[i+1][j],d[i][j]+num[i+1][j]};
d[i+1][j+1]=max{d[i+1][j+1],d[i][j]+num[i+1][j+1]};
最终,只要扫过d[R][1~R]取得最大值输出即可。
------------------------------------------------------------------------------------------------------------------------------------------------
【总结】
一遍AC。
------------------------------------------------------------------------------------------------------------------------------------------------
【代码】
1 /* 2 ID: icedrea1 3 PROB: numtri 4 LANG: C++ 5 */ 6 7 #include <iostream> 8 #include <fstream> 9 using namespace std; 10 11 int R; 12 int num[1001][1001],d[1001][1001]; 13 14 void change(int &r,int x) { if(x>r) r=x; } 15 16 int main() 17 { 18 ifstream in("numtri.in"); 19 ofstream out("numtri.out"); 20 21 in>>R; 22 for(int i=1;i<=R;++i) 23 for(int j=1;j<=i;++j) in>>num[i][j]; 24 25 d[1][1]=num[1][1]; 26 for(int i=1;i<R;++i) 27 for(int j=1;j<=i;++j) 28 { 29 change(d[i+1][j],d[i][j]+num[i+1][j]); 30 change(d[i+1][j+1],d[i][j]+num[i+1][j+1]); 31 } 32 33 int maxSum=0; 34 for(int j=1;j<=R;++j) change(maxSum,d[R][j]); 35 out<<maxSum<<endl; 36 37 in.close(); 38 out.close(); 39 return 0; 40 }