数字三角形
数字三角形
-
给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。(下面排列看起来可能有点不准确)
7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
-
借用最简单的动态规划的思想来考虑的话,解法其实相当简单,根据以下代码即可看懂思路:
#include<bits/stdc++.h> using namespace std; const int N = 505, INF = - 5e6 - 5; int n, a[N][N], f[N][N]; int main(){ scanf("%d", &n); for(int i = 1; i <= n; i ++) for(int j = 1; j <= i; j ++) scanf("%d", a[i] + j); for(int i = 1; i <= n; i ++) for(int j = 0; j <= i + 1; j ++) f[i][j] = INF;// 给每个状态位初始值全设为负无穷大 dp[1][1] = a[1][1]; for(int i = 2; i <= n; i ++) for(int j = 1; j <= i; j ++) f[i][j] = max(f[i - 1][j], f[i - 1][j - 1]) + a[i][j]; int res = INF; for(int i = 1; i <= n; i ++) res = max(res, f[n][i]); printf("%d", res); return 0; }
-
然而以上却是采用的二维数组来处理的问题,其实可以转化为一维数组来解决问题,但是思路描述上又变得不好理解了。这时突然想到之前背包问题中二维数组转化为一维数组好像都是固定的思路模板。
-
一维数组方案解决代码如下:
#include<bits/stdc++.h> using namespace std; const int N = 505, INF = - 5e6 - 5; int n, a[N][N], f[N]; int main(){ scanf("%d", &n); for(int i = 1; i <= n; i ++) for(int j = 1; j <= i; j ++) scanf("%d", a[i] + j); for(int i = 0; i <= n; i ++) // 这里需要变成从0开始,不太理解,先存疑。 f[i] = INF; f[1] = a[1][1]; for(int i = 2; i <= n; i ++) for(int j = i; j >= 1; j --) f[j] = max(f[j], f[j - 1]) + a[i][j]; int res = INF; for(int i = 1; i <= n; i ++) res = max(res, f[i]); printf("%d", res); return 0; }
-
仔细对比两套代码中核心处的状态转移计算处的代码:
for(int i = 2; i <= n; i ++) for(int j = 1; j <= i; j ++) f[i][j] = max(f[i - 1][j], f[i - 1][j - 1]) + a[i][j];
for (int i = 2; i <= n; i ++) for (int j = i; j >= 1; j --) f[j] = max(f[j] + a[i][j], f[j - 1] + a[i][j]);
-
这两组代码其实可以认为是等效的,具体分析起来确实挺头秃的,就先这样当板子记了。