方法一:动态规划
#include<iostream>
using namespace std;
const int N = 5e2 + 10, INF = 0x3f3f3f3f;
int g[N][N];
int f[N][N]; //f[i][j]表示从点(1,1)到点(i,j)的最大路径和!
int n;
int main()
{
cin >> n;
for (int i=1; i <= n; i ++)
for (int j=1; j <= i; j ++)
cin >> g[i][j]; //以二维矩阵来输入!
//处理边界为负数的情况:
for (int i=1; i <= n; i ++)
for (int j=0; j <= i+1; j ++)
f[i][j] = -INF;
f[1][1] = g[1][1]; //初始化!
for (int i=2; i <= n; i ++) //从前i行里选,选择到达第i行的最大路径和值!s
for (int j=1; j <= i; j ++) //遍历第i行的每一个元素!
f[i][j] = max(f[i-1][j], f[i-1][j-1]) + g[i][j]; //从前i-1行里选出最大的路径,加上该路径在第i行所获得的最大元素值!
int res = -INF;
for (int i=1; i <= n; i ++)
res = max(res, f[n][i]);
cout << res << endl;
return 0;
}
方法二:递归超时
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e2 + 10;
int n;
int g[N][N];
//递归的本质是:先递归到底部,然后回溯时计算更新!
int dfs (int x, int y)
{
if (x == n){ //递归到最后一层了!开始回溯更新计算,这才是递归的出口,而不是x>n就返回,越界有时候不一定是递归的出口
return g[x][y];
}
int s1, s2, res=0;
s1 = dfs (x+1, y);
s2 = dfs (x+1, y+1);
res += max(s1, s2) + g[x][y];
return res;
}
int main()
{
cin >> n;
for (int i=1; i <= n; i ++)
for (int j=1; j <= i; j ++)
cin >> g[i][j];
cout << dfs (1, 1) << endl;
return 0;
}}
方法三:递归的优化记忆化搜索
#include<iostream>
#include<cstring>
using namespace std;
const int N = 5e2 + 10;
int g[N][N];
int s[N][N]; //s[i][j]:表示从(i,j)点到底部的最大数字和,将其记录下来,这样对于同一个子树,就不用再重复枚举了!
int n;
/*
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
*/
int dfs (int x, int y)
{
if (s[x][y]) //记忆化剪枝:避免下面的两个dfs:保证了每个分支本来会被多次递归,现在只用递归一次即可!
return s[x][y];
if (x == n){ //走到底部了!
return s[x][y] = g[x][y]; //底部只有一个元素,所以直接赋值给s[x][y]进行记录!
}
s[x][y] = max(dfs(x+1, y), dfs(x+1, y+1)) + g[x][y];
return s[x][y];
}
int main()
{
cin >> n;
for (int i=1; i <= n; i ++)
for (int j=1; j <= i; j ++)
cin >> g[i][j];
dfs(1, 1);
cout << s[1][1] << endl;
return 0;
}
上图记忆化搜索,和下面的对比下:搞清楚返回值的问题:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 5e2 + 10;
int g[N][N];
int s[N][N]; //s[i][j]:表示从(i,j)点到底部的最大数字和,将其记录下来,这样对于同一个子树,就不用再重复枚举了!
int n;
/*
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
*/
int dfs (int x, int y)
{
if (s[x][y]) //记忆化剪枝:避免下面的两个dfs:保证了每个分支本来会被多次递归,现在只用递归一次即可!
return s[x][y];
if (x == n){ //走到底部了!
s[x][y] = g[x][y]; //底部只有一个元素,所以直接赋值给s[x][y]进行记录!
}
else s[x][y] = max(dfs(x+1, y), dfs(x+1, y+1)) + g[x][y];
return s[x][y];
}
int main()
{
cin >> n;
for (int i=1; i <= n; i ++)
for (int j=1; j <= i; j ++)
cin >> g[i][j];
cout << dfs(1, 1);
return 0;
}