HDU -- 數塔(ACM Step: 3.2.7)
阿新 • • 發佈:2018-12-14
一、概述
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; }