观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
在上面的样例中,从 7 → 3 → 8 → 7 → 5 7 \to 3 \to 8 \to 7 \to 5 7→3→8→7→5 的路径产生了最大权值。
第一个行一个正整数 r r r ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
单独的一行,包含那个可能得到的最大的和。
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
30
【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ r ≤ 1000 1\le r \le 1000 1≤r≤1000,所有输入在 [ 0 , 100 ] [0,100] [0,100] 范围内。
题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
本题是动态规划,即给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后把子问题的答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。
动态规划入门思路: dfs暴力 --> 记忆化搜索 --> 递推(转化成公式)
1dfs > 2记忆化搜索 > 3逆序递推 > 4顺序递推 > 5优化空间 !
记忆化搜索 = 暴力dfs + 记录答案
递归的过程:
“递” 的过程是: 分解子问题的过程。
“归” 的过程才是: 产生答案的过程。
“递” —> 自顶向下, “归” —> 自底向上 , 其中 “底” 是 递归搜索树 的底是最小的子问题的答案。
写出递推公式的方法:
递推 的公式 = dfs 向下 递归 的公式
递推 数组的初始值 = 递归 的边界(出口)
递归是向下,递推是向上,递推是小问题之和,还要算出最优的小问题
一般写的都是逆序递推(这里的逆是对层数而言的),从最高层要往上推,所以是+1,答案在上面,如果要写正序递推的话,改一下顺序就行了(-1),答案在下面。
本题要求走过的路径值最大,我们可以从最上方出发,把子问题拆成一步可以往正下或者下右走,然后将值返回当前记录答案的数组,不断遍历之后,最上方的数组就是答案。
#include
using namespace std;
int n;
vector<vector<int>> v(1010,vector<int> (1010));
vector<vector<int>> ans(1010,vector<int> (1010));
int main() {
cin >> n;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
cin >> v[i][j];
}
}
for(int i=n-1;i>=0;i--){
for(int j=0;j<n;j++){
ans[i][j]=max(ans[i+1][j],ans[i+1][j+1])+v[i][j];
}
}
cout << ans[0][0];
return 0;
}