練習一 數字三角形

2021-08-13 16:25:17 字數 1940 閱讀 2911

繞來繞去,又繞回這道經典的題了。

從洛谷上找到了這道題:cgg最帥了!

點開它,傳說中的數字三角形就出現在你的面前。

因為有題目我就不羅列了。

看到題目後有什麼想法?

很難?很簡單?

都不是!

你想到的應該是我們做動態規劃最重要的三步中的兩步(第一步好像我幫你做掉了)。

那就是設計狀態和轉態轉移方程。

那麼怎麼設計狀態呢?

還記得我們求數列最大值的時候怎麼做的嗎?

當前的部分的最大值,等於兩部分的最大值的最大值。

那麼我們這裡也可以借鑑這個思路去解決這個問題。

我們就可以設計這樣的狀態:

f[i][j]表示由點(i,j)向下走能得到的最大值。

那麼,我們的狀態轉移方程怎麼寫呢?其實很簡單:

f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];
a表示原數字三角形。

這樣**也就出來了:

#include

using

namespace

std;

int a[1005][1005];

int f[1005][1005];

int n;

int main()

}

for(int i=1;i<=n;i++)

for(int i=n-1;i>=1;i--)

}printf("%d",f[1][1]);

return

0;}

有的初學者可能比較蒙:為什麼一切都顯得那麼自然?

實際上如果你到了我這個角度也會發現這個題目很簡單。

但是我畢竟是要將給初學者聽的,所以我們來想一下怎麼想,怎麼思考。

首先二維是很顯然的(雖然我們可以用一維來解,這個過會在講),因為數字三角形就是個二維的,而數列是一維的。所以用二維去描述很顯然。

那麼我們就會想到用二維座標去描述每乙個點,那麼我們記錄什麼東西呢?

從上面到這個點得到的最大值?還是由這個點往下走的最大值?

很明顯後者更優,為什麼?

因為前者的狀態轉移方程並不好寫,考慮邊界的問題。

那麼我們就採取後者,然後就可以很自然地寫出狀態轉移方程,然後就得到程式了。

這就是我們的思考過程。

從這個過程,我們可以看出選擇狀態是個動態的過程。

狀態決定狀態轉移方程,而狀態轉移方程又反過來影響狀態。

因為你絕不想寫乙個特別複雜的狀態轉移方程,甚至寫不出方程。

所以需要不斷調整狀態。

那麼我們再來講講優化,怎麼做成一維。

我們來看一下這行**:

f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];
有什麼發現?

我們每次涉及的只有當前行的下面一行的最優值,而之前的根本沒有任何作用,所以我們完全能再計算後,用新的值去覆蓋以前的值,這樣只要一維就行了。

於是,狀態轉移方程就變成了:

f[j]=max(f[j],f[j+1])+a[i][j];
所以程式就變成了:

#include

using

namespace

std;

int a[1005][1005];

int f[1005];

int n;

int main()

}

for(int i=1;i<=n;i++)

for(int i=n-1;i>=1;i--)

}printf("%d",f[1]);

return

0;}

當然這個陣列有個美妙的名字叫做滾動陣列。

這就是我今天要講的。

數字三角形

題目描述 示出了乙個數字三角形。請編乙個程式計算從頂至底的某處的一條路 徑,使該路徑所經過的數字的總和最大。每一步可沿左斜線向下或右斜線向下走 1 三角形行數 25 三角形中的數字為整數 1000 輸入第一行為n,表示有n行 後面n行表示三角形每條路的路徑權 輸出路徑所經過的數字的總和最大的答案 樣...

數字三角形

description 有如下所示的數塔,要求從頂層走到底層,若每一步只能走到相鄰的結點,則經過的結點的數字之和最大是多少?input 輸入資料首先包括乙個整數c,表示測試例項的個數,每個測試例項的第一行是乙個整數n 1 n 100 表示數塔的高度,接下來用n行數字表示數塔,其中第i行有個i個整數,...

數字三角形

3 8 8 1 0 2 7 4 4 4 5 2 6 5 上圖給出了乙個數字三角形。從三角形的頂部到底部有很多條不同的路徑。對於每條路徑,把路徑上面的數加起來可以得到乙個和,和最大的路徑稱為最佳路徑。你的任務就是求出最佳路徑上的數字之和。input 1 5 7 3 8 8 1 0 2 7 4 4 4 ...