给定一个由n行数字组成的数字三角形,设计一个算法,计算出从三角形的顶至底的一条路径,使该路径所经过的数字总和最大。
示例
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
路径只能是左斜线向下或右斜线向下
这个示例:30
对于这个问题,可以从上往下(DP)和从下往上(DP)解决
从上往下(DP)
- 将每一个数值与左斜线向下的值相加,存到左斜线向下的位置
- 将每一个数值与右斜线向下的值相加,存到右斜线向下的位置
- 当一个数值有左斜向上和右斜向上时,需要比较大小,保留较大的值
- 最后遍历最后一行,找出最大值即可
7
10 15
18 16 15 //数值1拥有左斜向上和右斜向上,10+1<15+1,保留16
20 25 20 19
24 30 27 26 24
遍历最后一行,找出最大值30
#include <iostream>
using namespace std;
int main()
{
int n;
cout << "Input n :";
cin >> n;
int** arr = new int*[n];
for (int i = 0; i < n; i++)
arr[i] = new int[i + 1];
for(int i = 0; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
cin >> arr[i][j];
}
}
for (int i = 1; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
if (j == 0 )
arr[i][j] = arr[i - 1][j] + arr[i][j];//边界需要特殊处理
else if (j == i)
arr[i][j] = arr[i - 1][j - 1] + arr[i][j];//边界需要特殊处理
else
arr[i][j] = arr[i - 1][j - 1] + arr[i][j] > arr[i - 1][j] + arr[i][j] ? arr[i - 1][j - 1] + arr[i][j] : arr[i - 1][j] + arr[i][j];
}
}
int max = arr[n-1][0];
for (int i = 1; i < n; i++)
{
max = arr[n-1][i] > max ? arr[n-1][i] : max;
}
cout << "MAX IS " << max;
for (int i = 0; i < n; i++)
{
delete arr[i];
}
delete[] arr;
}
从下往上(DP)
- 该方法与从上往下相反,只需要将相邻两个数分别与右斜向上、左斜向上相加,保留最大值
- 最后[0][0]元素即为所求
30
23 21
20 13 10
7 12 10 10
4 5 2 6 5
直接取用[0][0]元素30
/* C++代码 */
#include <iostream>
using namespace std;
int main()
{
int n;
cout << "Input n :";
cin >> n;
int** arr = new int*[n];
for (int i = 0; i < n; i++)
arr[i] = new int[i + 1];
for(int i = 0; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
cin >> arr[i][j];
}
}
for(int i=n-2;i>=0;i--)
{
for (int j = 0; j <= i; j++)
{
arr[i][j] = arr[i][j] + arr[i + 1][j] > arr[i][j] + arr[i + 1][j + 1] ? arr[i][j] + arr[i + 1][j] : arr[i][j] + arr[i + 1][j + 1];
}
}
cout << "MAX IS " << arr[0][0];
for (int i = 0; i < n; i++)
{
delete arr[i];
}
delete[] arr;
}