数塔
问题描述:
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
已经告诉你了,这是个DP的题目,你能AC吗?
input:
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
output:
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input:
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
解题思路:
假设数据按Sample Input中所给数据排列。
则到达当前点的结点之和最大值(设为cmax)只和与它位于同一列的上一个点(假设为a)结点之和最大值(设为amax)以及a点左侧点的结点之和最大值(设为almax)有关。
很容易得出递推公式。
cmax = max(amax,almax)+当前点的值
具体细节见代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 到某数的最大值,
int main()
{
int n;
cin >> n; // 样例组数
for (int i = 0; i < n; i++)
{
int m;
cin >> m; // 每个样例行数
vector<vector<int> > a; // 保存原始数据
vector<vector<int> > c; // 到某点结点之和的最大值
for (int i = 1; i <= m; i++)
{
vector<int> b;
vector<int> e;
int d;
for (int j = 0; j < i; j++)
{
cin >> d;
b.push_back(d);
e.push_back(0);
}
c.push_back(e); // c初始化为全0
a.push_back(b); // 输入原始数据
}
c[0][0] = a[0][0]; // 第一个点结点之和的最大值
int max1 = a[0][0]; // 所有节点之和的最大值的初始值
for (int i = 1; i < m; i++)
for (int j = 0; j <= i; j++)
{
if (j == 0) // 某行最左边的数据
c[i][j] = c[i - 1][j] + a[i][j];
else if (j == i) // 某行最右边数据
c[i][j] = c[i - 1][j - 1] + a[i][j];
else // 递推方程
c[i][j] = max(c[i - 1][j], c[i - 1][j - 1]) + a[i][j];
if (c[i][j] > max1)
max1 = c[i][j]; // 更新节点之和最大值
}
cout << max1 << endl;
}
return 0;
}