文章首發
{% cq %}
動態規劃
(Dynamic programming)
{% endcq %}
數塔問題
有形如下圖所示的數塔,從頂部出發,在每一結點可以選擇向左走或是向右走,一直走到底層,要求找出一條路徑,使路徑上的值最大。
輸入
輸入數據首先包括一個整數C,表示測試實例的個數,每個測試實例的第一行是一個整數N(1 <= N <= 100),表示數塔的高度,接下來用N行數字表示數塔,其中第i行有個i個整數,且所有的整數均在區間[0,99]內。
輸出
對於每個測試實例,輸出可能得到的最大和,每個實例的輸出佔一行。
樣例輸入
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
樣例輸出
30
分析
{% blockquote David Levithan, Wide Awake %}
這道題如果用枚舉法(暴力思想),在數塔層數稍大的情況下(如31),則需要列舉出的路徑條數將是一個非常龐大的數目(2^30= 1024^3 > 10^9=10億)~~~
從頂點出發時到底向左走還是向右走應取決於是從左走能取到最大值還是從右走能取到最大值,只要左右兩道路徑上的最大值求出來了才能作出決策。
同樣,下一層的走向又要取決於再下一層上的最大值是否已經求出才能決策。這樣一層一層推下去,直到倒數第二層時就非常明瞭。
如數字2,只要選擇它下面較大值的結點19前進就可以了。所以實際求解時,可從底層開始,層層遞進,最後得到最大值。
結論:自頂向下的分析,自底向上的計算。
{% endblockquote %}
如果從下(倒數第二層)往上走,每次選最優解,可以少最後一層的步驟~~
代碼
#include<bits/stdc++.h>
using namespace std;
int dp[110][110];
int main(){
int n,t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
scanf("%d",&dp[i][j]);
}
}
for(int i=n-1;i>0;i--){
for(int j=1;j<=i;j++){ //每次與下兩個取最優
dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);
}
}
printf("%d\n",dp[1][1]);
}
return 0;
}
感謝劉老師