1. 程式人生 > >動態規劃(DP)之入門學習-數字三角形

動態規劃(DP)之入門學習-數字三角形

數字三角形案例

題目描述 Description

下圖給出了一個數字三角形,請編寫一個程式,計算從頂至底的某處的一條路徑,使該路徑所經過的數字的總和最大。
(1)每一步可沿左斜線向下或右斜線向下
(2)1 < 三角形行數 < 100
(3)三角形數字為0,1,…99
這裡寫圖片描述

輸入描述 Input Description

有很多個測試案例,對於每一個測試案例, 通過鍵盤逐行輸入,第1行是輸入整數(如果該整數是0,就表示結束,不需要再處理),表示三角形行數n,然後是n行數

輸出描述 Output Description

輸出最大值。

樣例輸入 Sample Input

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

樣例輸出 Sample Output

30

遞迴解法

解題思路

用二維陣列存放數字三角形。
D( r, j) : 第r行第 j 個數字(r,j從1 開始算)
MaxSum(r, j) : 從D(r,j)到底邊的各條路徑中,最佳路徑的數字之和。
問題:求 MaxSum(1,1)
典型的遞迴問題。
D(r, j)出發,下一步只能走D(r+1,j)或者D(r+1, j+1)。故對於N行的三角形:

if ( r == N)
 MaxSum(r,j) = D(r,j)
else
MaxSum( r, j) = Max{ MaxSum(r+1,j), MaxSum(r+1,j+1) } + D(r,j)

程式碼實現

#include <iostream>
#include <algorithm>

#define Max 101

using namespace std;

int D[Max][Max];

int num;

int MaxSum(int i, int j){
    if(i == num)
        return D[i][j];
    int x = MaxSum(i + 1, j);
    int
y = MaxSum(i + 1, j + 1); return max(x,y) + D[i][j]; } int main(int argc, char const *argv[]) { int i, j; cin >> num; for(i = 1; i <= num; i ++) for(j = 1; j <= i; j ++) cin >> D[i][j]; cout << MaxSum(1,1) << endl; return 0; }

時間複雜度

遞迴求解,會嚴重超時,因為出現重複計算,如下圖所示。深度遍歷每條路徑,存在大量重複計算。5行的總時間為:1+2+4+8+16=31=251則時間複雜度為 2n
這裡寫圖片描述

記憶遞迴動歸程式

解題思路

第一次計算MaxSum(r,j)值的時候,儲存下來,下次需要的時候,直接取出計算,這樣就避免了重複計算。時間複雜度為O(n2),因為三角形的數字總和為n(n+1)/2

程式碼實現

#include <iostream>
#include <algorithm>
#include "string.h"

#define Max 101

using namespace std;

int D[Max][Max];
int Max_Sum_arr[Max][Max];

int num;

int MaxSum(int i, int j){
    if(Max_Sum_arr[i][j] != -1)
        return Max_Sum_arr[i][j];
    if(i == num)
        Max_Sum_arr[i][j] = D[i][j];
    else{
        int x = MaxSum(i + 1, j);
        int y = MaxSum(i + 1, j + 1);
        Max_Sum_arr[i][j] = max(x,y) + D[i][j];
    }

    return Max_Sum_arr[i][j];
}

int main(int argc, char const *argv[])
{
    int i, j;

    cin >> num;

    for(i = 1; i <= num; i ++)
        for(j = 1; j <= i; j ++)
            cin >> D[i][j];
    memset(Max_Sum_arr,-1,sizeof(Max_Sum_arr));
    cout << MaxSum(1,1) << endl;
    return 0;
}

遞推型動歸程式

解題思路

從底向上遞推,出最後一行外,每一行的每個點的最大值等於自身加上下面一行對應左右兩個點的最大值,從下往上遞推,最頂部的即所求。比如下圖所示。首先最後一行的最大值就是它本身。倒數第二行第一個數7就是輸入的倒二行的第一個數2 + 4 和 2 +5 取最大值 。逐步遞推到頂部。

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

這裡寫圖片描述

程式碼實現

#include <iostream>
#include <algorithm>
#include "string.h"

#define Max 101

using namespace std;

int D[Max][Max];


int num;



int MaxSum(int num){
    int i, j;
    for(i = num - 1; i >= 1; i --)
        for(j = 1; j <= i; j ++){
            D[i][j] = max(D[i+1][j],D[i+1][j+1]) + D[i][j];
        }
    return D[1][1];
}
int main(int argc, char const *argv[])
{
    int i, j;

    cin >> num;

    for(i = 1; i <= num; i ++)
        for(j = 1; j <= i; j ++)
            cin >> D[i][j];
    cout << MaxSum(num) << endl;
    return 0;
}

動規解題的一般思路

1、將原問題分解為子問題

  • 把原問題分解為若干個子問題,子問題和原問題形式相同或類似,只不過規模變小了。子問題都解決,原問題即解決(數字三角形例)
  • 子問題的解一旦求出就會被儲存,所以每個子問題只需求解一次。

2、確定狀態

在用動態規劃解題時,我們往往將和子問題相關的各個變數的一組取值,稱之為一個“狀態”。一個“狀態”對應於一個或多個子問題,所謂某個“狀態”下的“值”,就是這個“狀態”所對應的子問題的解。

3、確定一些初始狀態(邊界狀態)的值

以“數字三角形”為例,初始狀態就是底邊數字,值就是底邊數字值。

4、確定狀態轉移方程

定義出什麼是“狀態”,以及在該 “狀態”下的“值”後,就要找出不同的狀態之間如何遷移――即如何從一個或多個“值”已知的“狀態”,求出另一個“狀態”的“值” 。狀態的遷移可以用遞推公式表示,此遞推公式也可被稱作“狀態轉移方程”。

能用動規解決的問題的特點

  1. 問題具有最優子結構性質。如果問題的最優解所包含的子問題的解也是最優的,我們就稱該問題具有最優子結構性質。
  2. 無後效性。當前的若干個狀態值一旦確定,則此後過程的演變就只和這若干個狀態的值有關,和之前是採取哪種手段或經過哪條路徑演變到當前的這若干個狀態,沒有關係。

參考資料

《程式設計導引及線上實踐》——北京大學資訊科學技術學院

相關推薦

動態規劃DP入門學習-數字三角形

數字三角形案例 題目描述 Description 下圖給出了一個數字三角形,請編寫一個程式,計算從頂至底的某處的一條路徑,使該路徑所經過的數字的總和最大。 (1)每一步可沿左斜線向下或右斜線向下 (2)1 < 三角形行數 < 100

由Leetcode詳解演算法 動態規劃DP

因為最近一段時間接觸了一些Leetcode上的題目,發現許多題目的解題思路相似,從中其實可以瞭解某類演算法的一些應用場景。 這個隨筆系列就是我嘗試的分析總結,希望也能給大家一些啟發。 動態規劃的基本概念 一言以蔽之,動態規劃就是將大問題分成小問題,以迭代的方式求解。 可以使用動態規劃求解的問題

演算法總結動態規劃DP

適用動態規劃的特點 所解決的問題是最優化問題。 所解決的問題具有“最優子結構”。可以建立一個遞推關係,使得n階段的問題,可以通過幾個k<n階段的低階子問題的最優解來求解。 具有“重疊子結構”的特點。即,求解低階子問題時存在重複計算。 詞典法 大家都知道,遞迴演算法一般都存在大量的重複計算,這會造成不

演算法動態規劃DP

前言 前言_ 我們遇到的問題中,有很大一部分可以用動態規劃(簡稱DP)來解。 解決這類問題可以很大地提升你的能力與技巧,我會試著幫助你理解如何使用DP來解題。 這篇文章是基於例項展開來講的,因為乾巴巴的理論實在不好理解。 注意:如果你對於其中某一節已經瞭解並且不

【演算法動態規劃動態規劃DP詳解

一、基本概念 動態規劃(dynamic programming)是運籌學的一個分支,是求解決策過程(decision process)最優化的數學方法。20世紀50年代初美國數學家R.E.Bellman等人在研究多階段決策過程(multistep d

動態規劃DP

first 個數 目的 進入 right 返回值 ase lines cal 在學習動態規劃前 , 先補充些有關遞歸的知識 。      所謂的遞歸函數 就是調用自身函數的過程 ,因此是用棧來存儲的 。   遞歸函數的最終返回值 就是第一次調用函數的返回值 。   在寫

初探動態規劃DP

isp exit min 管理 應該 一行 註意 習慣 試圖 學習qzz的命名,來寫一篇關於動態規劃(dp)的入門博客。 動態規劃應該算是一個入門oier的坑,動態規劃的抽象即神奇之處,讓很多萌新 萌比。 寫這篇博客的目標,就是想要用一些容易理解的方式,講解入門動態規劃的真

01背包問題與動態規劃DP

clas const 解法 自己 沒有 end ostream 初始化 動手 解法一:我們先用最樸素的方法,著眼於每個物體是否進入背包,進行遍歷。 代碼如下: #include<iostream> #include<algorithm&

動態規劃DP演算法

    動態規劃相信大家都知道,動態規劃演算法也是新手在剛接觸演算法設計時很苦惱的問題,有時候覺得難以理解,但是真正理解之後,就會覺得動態規劃其實並沒有想象中那麼難。網上也有很多關於講解動態規劃的文章,大多都是敘述概念,講解原理,讓人覺得晦澀難懂,即使一時

對記憶化搜尋ms動態規劃dp的深入理解

    六月中旬了,馬上就要期末考試了,期末考試結束以後就要迎來緊張刺激的留校集訓,到那時部落格會更新的比較頻繁,而現在在準備期末考試,所以可能更新的部落格稍微少一些。    話不多說,今天來更一篇剛剛吃飯的時候關於記憶化搜尋和動態規劃的一些區別的思考。    記憶化搜尋(M

一道題看懂遞迴、深度搜索dfs、記憶化搜尋、動態規劃DP的差別!

有一個層數為n(n<=1000)的數字三角形。現有一隻螞蟻從頂層開始向下走,每走下一級,可向左下方向或右下方向走。求走到底層後它所經過數字的總和的最大值。 【輸入格式】 第一個整數為n,一下n行為各層的數字。 【輸出格式】 一個整數,即最大值。

HDU 1069.Monkey and Banana【動態規劃DP】【8月15】

A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a banana at the roof of a building, and at the mean time, pr

演算法筆記:動態規劃DP初步

專題:動態規劃(DP)初步 內容來源:《挑戰程式設計競賽》(第2版)+《演算法競賽入門經典》(第2版)+網上資料整理彙總 一、引入         動態規劃程式設計是對解最優化問題的一種途徑、一種方法,而不是一種特殊演算法。不像前面所述的那些搜尋或數值計算那樣,具有

多重部分和問題動態規劃DP

注:文章內容源自《挑戰程式設計競賽》(第二版) 原題 多重部分和問題 有n種不同大小的數字ai,每種各mi個。判斷是否可以從這些數字之中選出若干使它們的和恰好為K。 1<=n<=100 1<=ai,mi<=100000 1<=K<=100

我的總結-動態規劃DP

        學習演算法已經有1年半左右了。學演算法刷題必不可少,剛開始的時候遇到題出不了只是坐那苦想,然後某一天得知上網可以搜到解題報告,興沖沖開啟網頁,在百度搜索框裡貼上了題目名字,回車,確實有各種題解。當時年少不懂網路的強大還感嘆了一把。點開之後發現,幾乎所有解題報

動態規劃DP通俗講解

動態規劃的本質不在於是遞推或是遞迴,也不需要糾結是不是記憶體換時間。理解動態規劃並不需要數學公式介入,只是完全解釋清楚需要點篇幅…首先需要明白哪些問題不是動態規劃可以解決的,才能明白為神馬需要動態規劃。不過好處時順便也就搞明白了遞推貪心搜尋和動規之間有什麼關係,以及幫助那些總是把動規當成搜尋解的同學建立動規的

[dp] Codeforces 429B B. Working out動態規劃DP

作者:Accagain 原題 B. Working out time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output

Leetcode題解動態規劃4最大子序和打家劫舍

題目:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/23/dynamic-programming/57/ 題目描述: 打家劫舍 你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有

Leetcode題解動態規劃3最大子序和

題目:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/23/dynamic-programming/56/ 題目描述:   最大子序和 給定一個整數陣列 

Leetcode題解動態規劃2 買賣股票的最佳時機

題目:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/23/dynamic-programming/55/ 題目描述: 給定一個數組,它的第 i 個元素是一支給定股票第