三道動態規劃題

2021-10-19 11:00:33 字數 3116 閱讀 3578

三道簡單的動態規劃題

有 m x n 個格仔,機械人在最左上角的格仔,星星在最右下角的格仔。機械人只能向左和向下走。

問:機械人拿到星星,總共有多少種拿法?

如下圖:

思路:問題其實就是從左上角走到右下角,有多少種走法。

如果倒過來看,站在右下角的角度,走到右下角,只有2種可能:

一是從右下角格仔的左邊走來;二是從右下角格仔的上方走來。

所以,假設走到右下角格仔的左邊的格仔有 x 種走法,走到右下角格仔的上面的格仔有 y 種走法,

那麼,走到星星的位置總共就是有 x + y 種走法。

想到這裡,自然會去想,走到左邊格仔和走到上面格仔分別有多少種走法呢,即 x 和 y 應怎麼計算呢?

當然仍然是由目標格仔的左邊和上面的格仔的數字加起來。

於是,這道題很自然的就變成了一道填表題:

假設目標格仔的下邊是 u 和 v,那麼公式為:

array[u][v] = array[u-1][v] + array[u][v-1]
現在來考慮邊界條件:

u-1 和 v-1 都必須大於等於0,即,u和v都大於1;

那麼,當 u 或 v 為 0 的時候,array[u][v]是多少呢?

閱讀題目,自然而然地知道,當u為0或v為0,即第1排和第1列中的所有格仔都應該填1,即到達這樣的格仔只有一種走法。

於是,公式更新為:

當 u == 0 或 v == 0,

array[u][v] = 1

當其他時候,

array[u][v] = array[u-1][v] + array[u][v-1]

第一排和第一列先都填上1,然後其他格仔就順著填就填出來了。右下角的格仔自然最後也就填出來了。

程式如下:

class

solution

for(

int i=

0; i

)for

(int i=

0; i

)for

(int i=

1; i

int result = array[m-1]

[n-1];

for(

int i=

0; i

)delete

array;

return result;}}

;

第2題和第1題很像。仍然是 m x n 個格仔,機械人從左上角到右下角拿星星。

不同之處是, m x n 個格仔中會放置若干個障礙物,遇到障礙物自然被阻擋不能前進。

問:機械人拿到星星有多少種方法?

如下圖:

思路:首先,要想一下,障礙物如何表示。這很簡單,令有障礙物的格仔的數字為 -1 即可。

然後,我們要想一下 array[u][v] 的公式該怎麼改寫了。

假設目標格仔的上面是障礙物,那麼 array[u][v] = array[u-1][v] + 0;

假設目標格仔的左邊是障礙物,那麼 array[u][v] = array[u][v-1] + 0;

假設上面和左邊都是障礙物,那麼自然 array[u][v] = 0

現在,要開始考慮令 u-1 < 0 和 v-1 < 0 的情況,即第一排和第一列,該如何初始化?

上一題中,第一排和第一列都是初始化為 1 的;但是現在有障礙物之後,就不能都初始化為 1 了。

初始化完第一排和第一列之後,剩下的所有格仔就依然用填表法即可解決。**如下:

class

solution}}

for(

int j=

1; j

)break;}

else

}for

(int i=

1; i

)break;}

else

}for

(int i=

1; i

return obstaclegrid[m-1]

[n-1];}};

有乙個 m x n 的格仔矩陣。裡面填滿了非負整數。要求:從左上角到右下角找一條路徑,使得這條路徑上所有的數字相加之和最小。

如下圖:

思考:這道題最直觀的思考,很可能是這樣的:

左上角的格仔就像是一棵二叉樹的root,它的左兒子是下面的格仔,右兒子是右邊的格仔。

然後左兒子和右兒子又分別有自己的左右子樹。這就構成了一棵龐大的二叉樹。

再然後就是遍歷這棵二叉樹中能到達右下角葉子節點的所有路徑,找出其中的最小值。

讀者可以畫一畫,這棵二叉樹中有太多冗餘的部分。所以生成這顆二叉樹再計算肯定不是正解。

為了避免生成冗餘的部分,就要生成一種有向無環圖。當這個有向無環圖生成完畢之後,還要遍歷以找到最小值。這2個過程都是比較複雜的,而且也比較耗時。

有了之前的2題做啟發,這道題也倒過來想呢?

好了,想到這裡,我們忽然發現,這道題也是可以用填表法來填的啊!只不過要倒著推。

**如下:

class

solution

result.

push_back

(vecrow);}

result[m-1]

[n-1

]= grid[m-1]

[n-1];

for(

int col=n-

2; col>=

0; col--

)for

(int row=m-

2; row>=

0; row--

)for

(int i = m-

2; i >=

0; i--)}

return result[0]

[0];}};

(完)

三道題理解動態規劃

動態規劃是演算法導論中介紹的最重要的幾種基本演算法之一,因為好長時間沒有看書,再加上原來就理解的不深入,所以早就忘的差不多了,這兩天正好因為一道面試題複習一下。用幾句話描述動態規劃問題如下 乙個問題可以分解若干子問題,每乙個子問題為一種狀態,求出每乙個狀態的最優解,進而在它的幫助下求出下乙個狀態的最...

刷題86 動態規劃(三)

題目鏈結題目描述 給定乙個非負整數 num。對於 0 i num 範圍中的每個數字 i 計算其二進位制數中的 1 的數目並將它們作為陣列返回。示例 1 輸入 2 輸出 0,1,1 示例 2 輸入 5 輸出 0,1,1,2,1,2 高階 題目分析 法一 動態規劃 找規律 奇數二進位制中1的個數比前乙個...

LeetCode刷題 動態規劃(三)

最長公共子串行問題,最基本的問題是在兩個字串中找出最長公共字串。方法是使用雙指標 i,j遍歷兩個字串,建立二維 dp 陣列,通過填表獲得結果。1143,最長公共子串行,medium 583,兩個字串的刪除操作,medium 712,兩個字串的最小ascii刪除和,medium 1143,最長公共子串...