動態(tài)規(guī)劃介紹
1. 前言
本節(jié)內容是動態(tài)規(guī)劃算法系列之一:動態(tài)規(guī)劃的介紹,主要介紹了動態(tài)規(guī)劃的定義,什么樣的問題適合用動態(tài)規(guī)劃算法去求解,最后說明動態(tài)規(guī)劃算法在日常生活中的應用場景。
2. 什么是動態(tài)規(guī)劃?
動態(tài)規(guī)劃(Dynamic Programming)在數學上屬于運籌學的一個分支,是求解決策過程 (decision process)最優(yōu)化的數學方法,同時也是計算機科學與技術領域中一種常見的算法思想。
動態(tài)規(guī)劃算法與我們前面提及的分治算法相似,都是通過組合子問題的解來求解原問題的解。但是兩者之間也有很大區(qū)別:分治法將問題劃分為互不相交的子問題,遞歸的求解子問題,再將他們的解組合起來求解原問題的解;與之相反,動態(tài)規(guī)劃應用于子問題相互重疊的情況,在這種情況下,分治法還是會做很多重復的不必要的工作,他會反復求解那些公共的子問題,而動態(tài)規(guī)劃算法則對相同的每個子問題只會求解一次,將其結果保存起來,避免一些不必要的計算工作。
Tips: 這里說到的動態(tài)規(guī)劃應用于子問題相互重疊的情況,是指原問題不同的子問題之間具有相同的更小的子子問題,他們的求解過程和結果完全一樣。
動態(tài)規(guī)劃算法更多的時候是用來求解一些最優(yōu)化問題,這些問題有很多可行解,每個解都有一個值,利用動態(tài)規(guī)劃算法是希望找到具有最優(yōu)值的解。接下來,就讓我們具體看看動態(tài)規(guī)劃算法的求解思路及相關應用場景。
3. 動態(tài)規(guī)劃算法求解分析
3.1 適用問題
首先,在利用動態(tài)規(guī)劃算法之前,我們需要清楚哪些問題適合用動態(tài)規(guī)劃算法求解。一般而言,能夠利用動態(tài)規(guī)劃算法求解的問題都會具備以下兩點性質:
- 最優(yōu)子結構: 利用動態(tài)規(guī)劃算法求解問題的第一步就是需要刻畫問題最優(yōu)解的結構,并且如果一個問題的最優(yōu)解包含其子問題的最優(yōu)解,則此問題具備最優(yōu)子結構的性質。因此,判斷某個問題是否適合用動態(tài)規(guī)劃算法,需要判斷該問題是否具有最優(yōu)子結構。
Tips: 最優(yōu)子結構的定義主要是在于當前問題的最優(yōu)解可以從子問題的最優(yōu)解得出,當子問題滿足最優(yōu)解之后,才可以通過子問題的最優(yōu)解獲得原問題的最優(yōu)解。
- 重疊子問題: 適合用動態(tài)規(guī)劃算法去求解的最優(yōu)化問題應該具備的第二個性質是問題的子問題空間必須足夠” 小 “,也就是說原問題遞歸求解時會重復相同的子問題,而不是一直生成新的子問題。如果原問題的遞歸算法反復求解相同的子問題,我們就稱該最優(yōu)化問題具有重疊子問題。
Tips: 在這里,我們需要注意是,與適用動態(tài)規(guī)劃算法去求解的問題具備重疊子問題性質相反,前面我們介紹的分治算法遞歸解決問題時,問題的子問題都是互不影響,相互獨立的,這個也是我們在選用動態(tài)規(guī)劃算法還是分治法解決問題時的一個判斷條件。
3.2 算法步驟
在明確什么樣的問題適合用動態(tài)規(guī)劃算法去求解時,我們需要掌握動態(tài)規(guī)劃算法的求解步驟:
步驟 1: 刻畫一個最優(yōu)解的結構特征
適合用動態(tài)規(guī)劃算法求解的問題需要滿足最優(yōu)子結構的特征,所以在應用動態(tài)規(guī)劃算法時的第一步就是刻畫問題最優(yōu)解的結構,一般都是用一些數學方法去描述求解問題,用數學公式表明最優(yōu)解的結構特征。
步驟 2: 遞歸的定義最優(yōu)解的值
當應用動態(tài)規(guī)劃算法求解問題時,一般我們會遞歸的求解相同的子問題,這個時候,我們就需要去遞歸的定義最優(yōu)解的值,通常也是先用數學公式去遞歸定義。
步驟 3: 計算最優(yōu)解的值
當我們可以清楚的刻畫一個最優(yōu)解的結構特征及可以遞歸的定義出最優(yōu)解的值之和,一般我們就可以采用自底向上的方法逐步去計算每一個最優(yōu)解的值,大問題的最優(yōu)解的值依賴于小問題的最優(yōu)解的值,這個是動態(tài)規(guī)劃算法的核心思想。
步驟 4: 利用計算出的信息構造一個最優(yōu)解
前面的步驟 1,2,3 是動態(tài)規(guī)劃算法求解問題的基礎,如果我們僅僅需要一個最優(yōu)解的值,而不是需要了解最優(yōu)解本身,我們可以不用去執(zhí)行步驟 4;如果我們需要了解最優(yōu)解的具體情況,我們就需要在執(zhí)行步驟 3 的時候維護一些額外的信息,以便用來構造出一個最優(yōu)解。
4. 動態(tài)規(guī)劃的應用場景
在日常的生活學習中,遞動態(tài)規(guī)劃算法一般可以用來解決很多實際問題?,F在,我們就來看看動態(tài)規(guī)劃算法具體有哪些應用場景。
動態(tài)規(guī)劃示例問題:爬樓梯
假設你現在正在爬樓梯,一共需要經過 n 階樓梯你才可以到達樓頂。每次你可以爬 樓梯的 1 或 2 個臺階。請問一共有多少種不同的方法可以爬到樓頂?
現在,讓我們按照動態(tài)規(guī)劃算法的求解步驟我們來分析一下這個問題:
步驟 1: 刻畫爬樓梯問題一個最優(yōu)解的結構特征
情況 1:輸入 n=1;輸出為 1
解釋 1:有一種情況可以爬上樓頂, 爬 1 步,記為 1
情況 2:輸入 n=2;輸出為 2
解釋 2:有兩種情況可以爬上樓頂,分別為連續(xù)兩次爬一階樓梯和一次爬兩階樓梯,記為 1+1,2
情況 3:輸入 n=3;輸出為 3
解釋 3:有三種情況可以爬上樓頂,如情況 1 和 2 描述一樣,記為 1+1+1,2+1,1+2
通過分析可以知道,爬樓梯問題主要在于我們可以一次爬兩步或者一步,所以到達最后一階樓梯 n 時,我們可以從第 n-2 階樓梯爬兩步或者第 n-1 樓梯爬一步完成。
當我們需要知道最多有多少種方法可以爬上 n 階的樓梯時,我們需要分別知道爬上第 n-2 階樓梯最多有多少種方法,爬上第 n-1 階樓梯最多有多少種方法,然后爬上第 n 階樓梯的最多方法數量等于爬上第 n-1 階樓梯最多的方法數量加上爬上第 n-2 階樓梯最多的方法數量。
Tips: 在這里,我們可以發(fā)現爬樓梯問題滿足第 3 節(jié)我們定義的動態(tài)規(guī)劃算法需要具備的兩種性質,其中的最優(yōu)子結構就是:爬上 n 階樓梯的最多方法數包含爬上第 n-1 樓梯和第 n-2 階樓梯的最多方法數;重疊子問題:需要反復的計算爬各階樓梯的最多方法數。
步驟 2: 遞歸的定義爬 n 階樓梯最多的方法數
- 上 1 階臺階:有 1 鐘方法;
- 上 2 階臺階:有 1+1 和 2 兩種方法;
- 上 3 階臺階:到達第 3 階的方法總數是到達第 1 階和第 2 階方法的總和;
- 上 n 階臺階:到達第 n 階的方法總數就是到第 (n-1) 階和第 (n-2) 階的方法數之和。
綜上所述,我們可以知道爬 n 階樓梯的狀態(tài)轉移方程可以定義為:goStep (n) = goStep (n-1)+goStep (n-2)。動態(tài)規(guī)劃算法最重要的就是去定義這個狀態(tài)轉移方程,通過這個狀態(tài)轉移方程我們就可以很清楚的去計算。
步驟 3: 計算爬 n 階樓梯最多方法數的值
樓梯階數 n | 爬 n 階樓梯最多的方法數 |
---|---|
1 | 1 |
2 | 2 |
3 | goStep(1)+goStep(2)=1+2=3 |
4 | goStep(2)+goStep(3)=2+3=5 |
5 | goStep(3)+goStep(4)=3+5=8 |
6 | goStep(4)+goStep(5)=5+8=13 |
7 | goStep(5)+goStep(6)=8+13=21 |
8 | goStep(6)+goStep(7)=13+21=36 |
9 | goStep(7)+goStep(8)=21+36=57 |
步驟 4: 利用計算出的信息構爬 n 階樓梯每次走幾步的方法
其實在爬樓梯這個問題中,我們并不需要統(tǒng)計每次的具體爬樓梯方法,如果需要統(tǒng)計每次具體走法時,需要在計算的時候記錄之前的每一步走法,把信息全部記錄保留下來即可。
我們可以很明顯的發(fā)現,動態(tài)規(guī)劃算法很多時候都是應用于求解一些最優(yōu)化問題(最大,最小,最多,最少),這類問題在現實生活或者學習科研中經常會遇到,這是一種解決問題的思路與方法,希望大家可以好好思考。
5. 小結
本節(jié)主要介紹了動態(tài)規(guī)劃算法的定義及基本概念,在學完本節(jié)課程之后,需要明白什么樣的問題適合利用動態(tài)規(guī)劃求解,如何自己去設計一個動態(tài)規(guī)劃算法,以及我們日常生活中哪些應用場景適合用動態(tài)規(guī)劃思想解決問題。