1. 程式人生 > >數字三角形——簡單遞推dp

數字三角形——簡單遞推dp

    給定一個由 nn 行數字組成的數字三角形如下圖所示。試設計一個演算法,計算出從三角形 的頂至底的一條路徑(每一步可沿左斜線向下或右斜線向下),使該路徑經過的數字總和最大

在這裡插入圖片描述

輸入樣例:

5 
7 
3 8 
8 1 0 
2 7 4 4
4 5 2 6 5 

輸出樣例:

30

    思路:很明顯是用dp來解決,很容易啟發對遞迴思想的理解     既然要求第一層到最後一層的最長路徑,那麼肯定要遍歷一遍,如果從 11 遍歷到nndfs),每一層的最優情況我們都無從得知,因為後面的影響因素我們都無法預測,那麼還有另一種方法:就是每一個點往下都只有兩種情況,如果把這兩種情況都記錄下來,很明顯最多有 2

n2^n 種,非常複雜

    所以這裡要換一種討論最優解的思路,如果從第 nn 層遍歷到第 11 層,那麼我在遍歷的時候,通過比較儲存的值一定是從後往前的最優解!     那麼你可能會問,為什麼從前往後不能儲存最優解呢?因為從後往前是雙入口單出口,這一個出口就保證了答案的唯一性     而從前往後是單入口多出口,我們無法保證這多個出口哪一個才是最優解,如果直接將這兩個出口進行比較,只能保證是區域性最優,而不是全域性最優

    換一種說法,從上到下的時候我們要把答案交給下一層解決、下一層不知道、只能交給下下一層解決............,直到最後一層     而從下到上,我們已經知道了最後一層的解決辦法,返回上一層,上一層得到解決,返回上上一層.

...........,相當於dfs結束了返回的過程

    這題是動態規劃最水的一題大概,但是回過頭來細細思考,還是溫故而知新

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, a[105][105], dp[105][105]; 

int main(){
	scanf("%d", &n);
	for(int i=0; i<n; i++)
		for(int j=0; j<=i; j++)
			scanf("%d", &a[i][j]);
	for(int i=0; i<n; i++) dp[n-1][i] = a[n-1][i];
	
	for(int i=n-1; i>0; i--)
		for(int j=0; j<i; j++){
			dp[i-1][j] = max(dp[i-1][j], a[i-1][j] + dp[i][j]);
			dp[i-1][j] = max(dp[i-1][j], a[i-1][j] + dp[i][j+1]);
		}
		
	printf("%d\n", dp[0][0]);
}