# DP总结

2021年09月15日 阅读数：1

dp[i]+=dp[i-1]+dp[i-1]/dp[i+x]+=dp[i];

Language:Default
The Triangle
 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 45053 Accepted: 27208

Description

`73   88   1   02   7   4   44   5   2   6   5(Figure 1)`
Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base. Each step can go either diagonally down to the left or diagonally down to the right.

Input

Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 99.

Output

Your program is to write to standard output. The highest sum is written as an integer.

Sample Input

```5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5```

Sample Output

`30`

Source

## 基本思路

D( r, j) : 第r行第 j 个数字(r,j从1开始算)
MaxSum(r, j) : 从D(r,j)到底边的各条路径中，

D(r, j)出发，下一步只能走D(r+1,j)或者D(r+1, j+1)。故对于N行的三角形：

``````if ( r == N)
MaxSum(r,j) = D(r,j) else MaxSum( r, j) = Max{ MaxSum(r＋1,j), MaxSum(r+1,j+1) } + D(r,j)``````
`` ``

## 为何超时

``````若是采用递规的方法，深度遍历每条路径，存在大量重复计算。则时间复杂度为 2n,对于 n = 100 行，确定超时。
``````

## 改进代码

``````#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std; int D[MAX][MAX]; int n; int maxSum[MAX][MAX]; int MaxSum(int i, int j) { if (maxSum[i][j] != -1) return maxSum[i][j]; if (i == n) maxSum[i][j] = D[i][j]; else { int x = MaxSum(i + 1, j); int y = MaxSum(i + 1, j + 1); maxSum[i][j] = max(x, y) + D[i][j]; } return maxSum[i][j]; } int main() { int i, j; cin >> n; for (i = 1; i <= n; i++) for (j = 1; j <= i; j++) { cin >> D[i][j]; maxSum[i][j] = -1; } cout << MaxSum(1, 1) << endl; }``````

## 转化为递推

### “人人为我”型递推

``````#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;

int D[MAX][MAX]; int n; int maxSum[MAX][MAX]; int main() {  int i, j;  cin >> n;  for (i = 1; i <= n; i++)  for (j = 1; j <= i; j++)  cin >> D[i][j];  for (int i = 1; i <= n; ++i)  maxSum[n][i] = D[n][i];  for (int i = n - 1; i >= 1; --i)  for (int j = 1; j <= i; ++j)  maxSum[i][j] = max(maxSum[i + 1][j], maxSum[i + 1][j + 1]) + D[i][j];  cout << maxSum[1][1] << endl; }``````

### “我为人人”型递归

``````#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std;

int D[MAX][MAX]; int n; int maxSum[MAX][MAX]; int main() {  int i, j;  cin >> n;  for (i = 1; i <= n; i++)  for (j = 1; j <= i; j++)  cin >> maxSum[i][j];  for (int i = 1; i < n; i++)  {  for (int j = 1; j <= i; j++)  {  maxSum[i + 1][j] = max(maxSum[i + 1][j], maxSum[i + 1][j] + maxSum[i][j]);  maxSum[i + 1][j + 1] = max(maxSum[i + 1][j + 1], maxSum[i + 1][j + 1] + maxSum[i][j]);  }  }  int maxx = -9999999999;  for (int i = 1; i <= n; i++)  maxx = max(maxx, maxSum[n][i]);  cout << maxx << endl; }``````

``````这里说的人人为我型递归就是在求DP[i][j]的过程当中， 求出DP[i + 1][j]和DP[i + 1][j +1]的其中一个解。
``````

## 空间优化

``````节省空间，时间复杂度不变
``````
``````#include <iostream>
#include <algorithm>
#define MAX 101
using namespace std; int D[MAX][MAX]; int n; int * maxSum; int main() { int i, j; cin >> n; for (i = 1; i <= n; i++) for (j = 1; j <= i; j++) cin >> D[i][j]; maxSum = D[n]; //maxSum指向第n行 for (int i = n - 1; i >= 1; --i) for (int j = 1; j <= i; ++j) maxSum[j] = max(maxSum[j], maxSum[j + 1]) + D[i][j]; cout << maxSum[1] << endl; }``````

## 人人为我

``````状态i的值Fi由若干个值已知的状态值Fk,Fm,..Fy推出，如求和，取最大值
``````