數塔
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 36261 Accepted Submission(s): 21659
Problem Description
在講述DP算法的時候,一個經典的例子就是數塔問題,它是這樣描述的:
有如下所示的數塔,要求從頂層走到底層,若每一步只能走到相鄰的結點,則經過的結點的數字之和最大是多少?
已經告訴你了,這是個DP的題目,你能AC嗎?
有如下所示的數塔,要求從頂層走到底層,若每一步只能走到相鄰的結點,則經過的結點的數字之和最大是多少?

已經告訴你了,這是個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 Output
30
Source
Recommend
剛看了動態規划,就做了道dp的題目。雖然動態規划還沒整明白,但是感覺這道題還是很好理解的。
在做完這道題目之后我又回顧了一下書(算法導論)中所講:
“我們通常按如下四個步驟來設計一個動態規划的算法:
- 刻畫一個最優解的結構特征。
- 遞歸地定義最優解的值。
- 計算最優解的值,通常采用自底向上的方法。
- 利用計算出的信息構造一個最優解。”
我覺得這道題的解題步驟就完全可以用這個來描述:
1.首先,一個最優解的結構特征,即從頂層走到底層,其各個節點的最大數字之和的為最優解。
2.題目中要求走法為自頂向下,且每一步只能走到相鄰的節點,那么每個節點只有兩種選擇,即這個節點的兩個子節點;
那么這個節點的最優解就等於這個節點的值加上其兩個節點的最優解的最大值;
3.自底向上的求解。
4.我們所求出來的解就是我們所需要的答案,則第四步在這里可以忽略掉。
最后附上我的代碼:
我用數組a來接收數塔的值,則第三部可以表示為:a[i][j]的最優解=a[i][j]+max(a[i+1][j]的最優解,a[i+1][j+1]的最優解);
而數塔最底層節點的最優解就等於他本身的值,因為他只有一個;那么最底層的值已知,我們只需要從下往上遞推就可以了
即這三行代碼塊:
for(i=n-1;i>=0;i--)
for(j=0;j<=i;j++) a[i][j]=a[i][j]+max(a[i+1][j],a[i+1][j+1]);
AC代碼:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 6 int main() 7 { 8 int a[105][105]; 9 int t, n, i, j; 10 while(cin>>t) 11 { 12 while(t--) 13 { 14 cin>>n; 15 memset(a,0,sizeof(a)); 16 for(i=0;i<n;i++) 17 for(j=0;j<=i;j++) 18 cin>>a[i][j]; 19 for(i=n-1;i>=0;i--) 20 for(j=0;j<=i;j++) 21 a[i][j]=a[i][j]+max(a[i+1][j],a[i+1][j+1]); 22 cout<<a[0][0]<<endl; 23 } 24 } 25 return 0; 26 }