一、概述
1. 问题描述
一个由数字构成的塔,第i层有i个节点,,每个节点带有一个权值,用v[i]表示,问从塔顶走到塔底最大能够获得多少权值?每一步只能走向相邻的节点。一个5层的数塔如图1.1所示。
图1.1 5层的数塔
2. 问题链接
3. 问题截图
图1.12 问题截图
二、算法思路
一个n层的数塔,一共个节点,并且通过分析可以知道,问题的解需要从每一层中取得一个节点构成。
假设,构成问题的解的节点序列是,,
表示第i层的某节点,由于从塔顶到塔底的每一步只能走向相邻的下一层的节点,因此,可以推断出解序列的元素有如下关系:
下面以一个四层的数塔分析问题,数塔中的数字代表节点的编号。
1
2 3
4 5 6
7 8 9 10
问题所求是节点1作为根节点时,对应数塔的最大权值,通过分析,这个最大值是,节点2和节点3对应数塔的最大值中的较大者,即是节点2、3作为根节点时对应数塔的最大值中的较大者;要求节点2对应数塔的值,同样要分析它对应的下层节点中的最大值。通过分析,发现可以用递归的思想解决,同时,由于从上向下递归时,同一个子问题可能被多次求解,比如求解以节点2和节点3为根节点的最大值时,它们都要取得节点5对应数塔的最大值,这会导致一些不必要的工作量。
由于要求出所有节点作为根节点对应的最大权值,可以从下往上构造,这样可以保证对每个节点只需要计算一次。
因此算法从最后一层节点开始计算,他们对应的最大权值就是他们本身的权值,然后根据上述公式:,可以构造出上层的权值最大值。
三、算法实现
#include <iostream> // for cin, cout, endl
using std::cin;
using std::cout;
using std::endl;
const int MAXSIZE = ((1+100)*100)/2; // max of the number of elements of digit tower
unsigned int data[MAXSIZE]; // store the input data
unsigned int ans[MAXSIZE]; // ans for answer, the data structure that construct the result, ans[0] is always the result
int input(); // for input data
unsigned calculate(int); // for calculate result
void print(unsigned); // for print result
int main()
{
int T, n;
unsigned m;
cin >> T;
for(int i=0; i<T; i++){
n = input();
m = calculate(n);
print(m);
}
return 0;
}
// read input data, return the depth of digit tower
int input()
{
int ret, n;
cin >> ret;
n = ((ret+1)*ret)/2; // total input data
for (int i=0; i<n; i++)
cin >> data[i];
return ret;
}
// calculate the result, n indicate the depth of digit tower, return the result of depth of n
unsigned calculate(int n)
{
int ele_num = ((1+n)*n)/2; // the actual number of elements in digit tower
int i, j, k;
// calculate the max value of the elements of last layer,
// max value is itself because they do not have next layer element when they be treated as the first node of digit tower
for (i=ele_num-1, j=n; j>0; i--, j--)
ans[i] = data[i];
// i indicate the node that it is currently calculated for max value
// j indicate the layer of node i
// k keep track of the num of node of layer j, when k reach 0, j incicate the prior layer
for (j=n-1, k=j; i>=0; i--, k--){
if(k == 0)
k = --j;
// the next layer node that related with i is node i+j and i+j+1
if(ans[i+j] < ans[i+j+1])
ans[i] = ans[i+j+1]+data[i];
else
ans[i] = ans[i+j]+data[i];
}
return ans[0];
}
// print the result
void print(unsigned n)
{
cout << n << endl;
}