題目連結:數字三角形
思路
dp:金字塔頂的元素為起點,金字塔每行的最左側數字只能從上一層的最左側數字到達,如7 -> 3 -> 8 -> 2 -> 4,這些數字中的每一個(除起點7外)都只能從上一層的最左側數字到達,遞推公式為dp[i][1] = max(dp[i][1], num[i][1] + dp[i - 1][1]
,最右側數字同理,遞推公式為dp[i][i] = max(dp[i][i], num[i][i] + dp[i - 1][i - 1]
,而中間的數字可以由上層相鄰的兩個數字到達,遞推公式為dp[i][j] = max(dp[i][i], num[i][j] + dp[i - 1][j - 1], num[i][j] + dp[i - 1][j]
。
最佳化:由於儲存時使用的邊界值為1,所以金字塔的最左側和最右側的數字的遞推公式可以統一為dp[i][j] = max(dp[i][i], num[i][j] + dp[i - 1][j - 1], num[i][j] + dp[i - 1][j]
,然後發現每次遞推時只需要使用兩層的資料,所以將空間複雜度最佳化為O(2 * n),然後每次使用第一層計算出第二層之後,第一層的dp陣列就不會再被使用,此時將第二層的dp陣列賦值給第一層的dp陣列,再用此時的第一層的dp陣列計算出第二層的dp陣列,一直遞推即可得到第r層的dp陣列,然後再對第r層的dp陣列取最大值即可得到結果。
程式碼
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5 + 10;
int dp[2][N], num[N];
int main() {
int r;
cin >> r;
for (int i = 1; i <= r; i++) {
for (int j = 1; j <= i; j++) {
cin >> num[j];
}
for (int j = 1; j <= i; j++) {
dp[1][j] = num[j] + max(dp[0][j], dp[0][j - 1]);
}
swap(dp[0], dp[1]);
}
int res = 0;
for (int i = 1; i <= r; i++) {
res = max(res, dp[0][i]);
}
cout << res << endl;
return 0;
}