關於 DP 的一些內容

0.關於

        動態規劃是編程解題的一種重要手段。1951 年美國數學家 R.Bellman 等人,根據一類多階段問題的特色,把多階段決策問題變換爲一系列互相聯繫的單階段問題,而後逐個加以解決。與此同時,他提出瞭解決這類問題的「最優化原理」,從而建立了解決最優化問題的一種新方法:動態規劃
        動態規劃算法一般用於求解具備某種最優性質的問題。在這類問題中,可能會有許多可行解。每個解都對應於一個值,咱們但願找到具備最優值的解
        咱們能夠用一個表來記錄全部已解的子問題的答案。無論該子問題之後是否被用到,只要它被計算過,就將其結果填入表中。這就是動態規劃法的基本思路。具體的動態規劃算法多種多樣,但它們具備相同的填表格式算法

1.基本概念

        · 階段:把所給問題的求解過程恰當地分紅若干個相互聯繫的階段,以便於求解。過程不一樣,階段數就可能不一樣。描述階段的變量稱爲階段變量,經常使用 k 表示。階段的劃分,通常是根據時間和空間的天然特徵來劃分,但要便於把問題的過程轉化爲多階段決策的過程。
        · 狀態:狀態表示每一個階段開始面臨的天然情況或客觀條件,它不以人們的主觀意志爲轉移,也稱爲不可控因素。一般一個階段有若干個狀態,狀態一般能夠用一個或一組數來描述,稱爲狀態變量。
        · 決策:表示當過程處於某一階段的某個狀態時,能夠作出不一樣的決定,從而肯定下一階段的狀態,這種決定稱爲決策。不一樣的決策對應着不一樣的數值,描述決策的變量稱決策變量。
        · 狀態轉移方程:動態規劃中本階段的狀態每每是上一階段的狀態和上一階段的決策的結果,由第 i 段的狀態 f(i) ,和決策 u(i) 來肯定第 i+1 段的狀態。狀態轉移表示爲 F(i+1) = T(f(i),u(i)) ,稱爲狀態轉移方程。
        · 策略:各個階段決策肯定後,整個問題的決策序列就構成了一個策略,對每一個實際問題,可供選擇的策略有必定範圍,稱爲容許策略集合。容許策略集合中達到最優效果的策略稱爲最優策略。編程

動態規劃必須知足最優化原理與無後效性。數組

        · 最優化原理:「一個過程的最優決策具備這樣的性質:即不管其初始狀態和初始決策如何,其從此諸策略對以第一個決策所造成的狀態做爲初始狀態的過程而言,必須構成最優策略」。也就是說一個最優策略的子策略,也是最優的。
        · 無後效性:若是某階段狀態給定後,則在這個階段之後過程的發展不受這個階段之前各個狀態的影響。優化

舉個栗子

來看一道題目。code

可憐的可樂機要回家,已知小可樂機在 左下角 (1,1) 位置,家在 右上角 (n,n) 座標處。小可樂機走上一個格子 (i,j) 會花費必定的體力 a[i][j],並且小可樂機只會往家的方向走,也就是隻能往上,或者往右走。小可樂機想知道他回到家須要花費的最少體力是多少, 求你幫幫小可樂機吧qwq數學

例以下圖所示,格子中的數字表明走上該格子花費的體力:
可樂機回家.png
對於該圖來講,最優策略已在圖上標出,最少花費體力爲:3 + 2 + 4 + 3 = 123 + 2 + 4 + 3 = 12。class

咱們把走到一個點看作一個狀態,對小可樂機來講,走到一個點只有兩種方式,一個是從下面走到該點,一種是從左邊走到該點。那麼點 (i,j) 要麼是從 (i-1,j) 走到 (i,j),要麼是從點 (i,j-1) 走到 (i,j)。變量

因此從哪一個點走到 (i,j) 就是一個 決策。接下來,咱們用 dp(i,j) 來表明走到點 (i,j) 一共花費的最少體力。
咱們須要花費最少力氣走到家,因此能夠獲得狀態轉移方程:dp(i,j) = min(dp(i-1,j), dp(i,j-1)) + a[i][j] 。根據轉移方程,咱們能夠推出走到每一個點花費的最少體力。原理

對於圖中的邊界點,要在轉移前加上判斷是否爲邊界,如:點 (1,3) 只能從點 (1,2) 走過來,點 (3,1) 只能從點 (2,1) 走過來等等。循環

動態規劃的題目的核心是寫出狀態轉移方程,對於一個動態規劃的題目,若是咱們能寫出轉移方程那麼代碼實現就變得簡單多了。大部分的動態規劃題目,在計算出轉移方程後,能夠用相似於遞推的循環結構,來寫出代碼。

主要代碼

int a[100][100]; // a數組表明在點(i,j)花費的體力
int dp[100][100]; // dp數組表明走到點(i,j)一共花費的最少體力
dp[1][1] = 0;
for (int i = 1; i <= n; i++) 
{
    for (int j = 1; j <= n; j++)
    {
        if (i == 1 && j == 1) 
        {
            continue;
        } 
        else if (i == 1) //邊界點
        { 
            dp[i][j] = dp[i][j-1] + a[i][j];
        } 
        else if (j == 1)  //邊界點
        {
            dp[i][j] = dp[i-1][j] + a[i][j];
        } 
        else 
        {
            dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + a[i][j]; //轉移方程
        }
    }
}
相關文章
相關標籤/搜索