• 沒有找到結果。

Dynamic Programming (1)

N/A
N/A
Protected

Academic year: 2022

Share "Dynamic Programming (1)"

Copied!
29
0
0

加載中.... (立即查看全文)

全文

(1)

Dynamic Programming (1)

by music960633

(2)

課程內容 課程內容

• 1. 什麼是 DP ?

• 2. Top down / Bottom up

• 3. 「狀態」、「狀態轉移」

• 4. 取餘數

(3)

什麼是 DP 什麼是 DP

• Dynamic programming ,動態規劃

• 將一個問題分成許多子問題,遞迴求解,最後再由子問題的答案 得到原本問題的答案 ( 類似 D&C)

• 相同的子問題會出現不只一次 ( 與 D&C 不同 )

• 將子問題的答案記錄起來

• 避免對相同的問題再遞迴一次

• 用空間換取時間

(4)

Example 1 Example 1

• 用 1*2 的骨牌填滿 2*n 的格子,共有幾種排法?

(5)

Example 1 Example 1

• 用 1*2 的骨牌填滿 2*n 的格子,共有幾種排法?

• Sol:

• 以 f(n) 表示填滿 2*n 格子的方法數

• 觀察最後一格放置骨牌的情形:

f(n-1) f(n-2)

(6)

Example 1 Example 1

• 用 1*2 的骨牌填滿 2*n 的格子,共有幾種排法?

• Sol:

• 以 f(n) 表示填滿 2*n 格子的方法數

• 觀察最後一格放置骨牌的情形:

• f(n)=f(n-1)+f(n-2)

• 初始條件: f(1)=1, f(2)=2

• 費氏數列

(7)

Example 1 Example 1

• 實作

• 最簡單遞迴版本

• 缺點:太慢

• 時間複雜度: O(f(n))

• 解決方法:使用陣列記錄答案

4 3

2 1

2

5

3

2 1

(8)

Top down Top down

• 將答案記錄起來,如果遇到相同的問題,則直接查表

• 時間複雜度: O(n)

4 3

2 1

2

5

3 3

(9)

Bottom up Bottom up

• 用迴圈先把答案全部算出來

• 時間複雜度: O(n)

(10)

Top down vs Bottom up Top down vs Bottom up

• Top down:

• 只要知道遞迴式就可以了,剩下交給遞迴跑

• code 一般為遞迴函式

• 注意遞迴過深

• Bottom up

• 子問題一定要比母問題先跑到 ( 注意迴圈跑法 )

• code 一般為 for 迴圈

(11)

Example 2 Example 2

• 將 n 個排成一列的格子塗上紅、綠、藍三種顏色,且藍綠不可相

鄰,問有幾種塗法?

(12)

Example 2 Example 2

• 將 n 個排成一列的格子塗上紅、綠、藍三種顏色,且藍綠不可相 鄰,問有幾種塗法?

• Sol:

• 設 f(n) 為塗 n 格的方法數

• f(n)=...

• 糟糕,遞迴式不知道怎麼寫

(13)

Example 2 Example 2

• 將 n 個排成一列的格子塗上紅、綠、藍三種顏色,且藍綠不可相 鄰,問有幾種塗法?

• Sol:

• 設 f(n,0) 為塗 n 格,且最後一格為紅色的方法數

• 設 f(n,1) 為塗 n 格,且最後一格為綠色的方法數

• 設 f(n,2) 為塗 n 格,且最後一格為藍色的方法數

• 遞迴式

• f(n,0)=f(n-1,0)+f(n-1,1)+f(n-1,2)

• f(n,1)=f(n-1,0)+f(n-1,1)

• f(n,2)=f(n-1,0)+f(n-1,2)

• 初始條件: f(1,0)=f(1,1)=f(1,2)=1

• 最後答案: f(n,0)+f(n,1)+f(n,2)

(14)

Example 2 Example 2

• Top down

(15)

Example 2 Example 2

• Bottom up

(16)

「狀態」、「狀態轉移」

「狀態」、「狀態轉移」

• 狀態

• Example 1: f(n) 表示填滿 2*n 格子的方法數

• Example 2:

• f(n,0) 為塗 n 格,且最後一格為紅色的方法數

• f(n,1) 為塗 n 格,且最後一格為綠色的方法數

• f(n,2) 為塗 n 格,且最後一格為藍色的方法數

• 在以上兩個例子中,我們都定義了函式參數所代表的意義,或是陣列索引值所 代表的意義

• f(n,m) 中的 n,m

• dp[n][m] 中的 n,m

• 狀態:用一些數字來「唯一」表示一個子問題

(17)

「狀態」、「狀態轉移」

「狀態」、「狀態轉移」

• 狀態轉移

• Example 1: f(n)=f(n-1)+f(n-2)

• Example 2:

• f(n,0)=f(n-1,0)+f(n-1,1)+f(n-1,2)

• f(n,1)=f(n-1,0)+f(n-1,1)

• f(n,2)=f(n-1,0)+f(n-1,2)

• 在以上兩個例子中,我們可以用一些方程式表示如何由其他的子問題結 果得到一個問題的答案

• 狀態轉移:如何由其他的狀態得到某個狀態的值

(18)

「狀態」、「狀態轉移」

「狀態」、「狀態轉移」

• 定義狀態時該注意的事

• 1. 狀態是否太多? ( 太多陣列開不下 )

• 2. 是否能導出狀態轉移式? ( 如 Example 2)

• 定出狀態且找出狀態轉移式之後

• 1. 時間複雜度是否合理?

• 2. 若不合理,能不能對狀態轉移做優化?

• 3. 若還是不行,試試看用其他方法定義狀態

• 如何找到正確的狀態定義方式?

• 靠經驗

• 靠靈感

(19)

Example 3 Example 3

• 用 1*2 和 1*3 的 L 型骨牌填滿 2*n 的格子,共有幾種排法?

• 定義狀態

• f(n) 表示填滿 2*n 格子的方法數

• 狀態是否太大? No

• 狀態轉移

• 同樣考慮最後一格的放法,放 1*2 的 case 已在 Example 1 討論過,因此 只討論放 L 型骨牌的 case

(20)

Example 3 Example 3

• 因為兩種情況是上下對稱的,因此只考慮一種方向

• 最後放 1*2 : f(n-1)+f(n-2)

• 最後放 L 型:

f(n-3) f(n-4) f(0)=1

(21)

Example 3 Example 3

• 因為兩種情況是上下對稱的,因此只考慮一種方向

• 最後放 1*2 : f(n-1)+f(n-2)

• 最後放 L 型: 2[f(n-3)+f(n-4)+...+f(1)+f(0)]

• 狀態轉移

• f(n)=f(n-1)+f(n-2)+2[f(n-3)+f(n-4)+...+f(1)+f(0)]

• O(n) 時間轉移

• 是否合理? O(n2) 好像不太好

• 能不能優化呢?

(22)

Example 3 Example 3

• 優化 f(n)=f(n-1)+f(n-2)+2[f(n-3)+f(n-4)+...+f(1)+f(0)]

• 使用變數記錄前綴和

• 若使用 bottom up ,可以用一個變數 (tmp) 記錄 f(0)+f(1)+...+f(n-3)

,如此可讓轉移變成 f(n)=f(n-1)+f(n-2)+2tmp , O(1) 轉移

• 化簡轉移式

• f(n-1)=f(n-2)+f(n-3)+2[f(n-4)+f(n-5)+...+f(1)+f(0)]

• f(n-1)+f(n-3)=f(n-2)+2[f(n-3)+f(n-4)+f(n-5)+...+f(1)+f(0)]

• 得到 2[f(n-3)+f(n-4)+...+f(1)+f(0)]=f(n-1)-f(n-2)+f(n-3)

• 轉移式變成 f(n)=2f(n-1)+f(n-3) , O(1) 轉移

(23)

Example 3 Example 3

• 另外一種狀態定義方式

• f(n,0): 鋪滿 2*n 的方法數

• f(n,1): 鋪滿 2*n 且下面多一格的方法數

2*f(2,1)

(24)

Example 3 Example 3

• 另外一種狀態定義方式

• f(n,0): 鋪滿 2*n 的方法數

• f(n,1): 鋪滿 2*n 且下面多一格的方法數

• 狀態轉移

• f(n,0)=f(n-1,0)+f(n-2,0)+2f(n-2,1)

• f(n,1)=f(n-1,0)+f(n-1,1)

• 初始狀態

• f(0,0)=1, f(0,1)=0

• f(1,0)=1, f(1,1)=1

• f(2,0)=2, f(2,1)=2

(25)

取餘數 取餘數

• 在計算方法數的題目中,我們常看到「請輸出答案除以 M 的餘 數」

• 以 Example 3 來說, f(28)=1914332891 ,如果 n 到很大 (100

萬 ) ,則一定要用到大數,但大部分不想要那麼麻煩,因此會要 求輸出餘數即可

• 加減乘法可以直接取餘數,除法則不行

• 小心在 mod 之前就 overflow ,因此建議開 long long( 尤其乘

法 )

(26)

取餘數 取餘數

• 若 Example 3 要求輸出答案除 1000007 的餘數

(27)

Example 4 Example 4

• 給一個正整數陣列,現在要從裡面取出一些數,但兩數不能相鄰

,求取出數字和的最大值

• Ex: arr[] = {1,4,2,3,5} ,則取出 4 和 5 有最大總合 9

(28)

Example 4 Example 4

• 定義狀態

• 假設索引值從 1 開始

• f(n) 為從 arr[1] 到 arr[n] 中取出數字,且有取到 arr[n] 的總合最大值

• 狀態轉移

• 因為數字不為負的,因此選擇的兩個數字之間一定間格 1 或 2

• 如果取了 arr[n] ,則上一個取到的數字為 arr[n-2] 或 arr[n-3]

• f(n)=max(f(n-2),f(n-3))+arr[n]

• 最後答案

• max(f(N), f(N-1))

(29)

Example 4 Example 4

• 另外一個解法

• 定義狀態

• f(n,0) 為從 arr[1] 到 arr[n] 取數字,且沒有取到 arr[n] 的總合最大值

• f(n,1) 為從 arr[1] 到 arr[n] 取數字,且有取到 arr[n] 的總合最大值

• 狀態轉移

• 如果沒有取到 arr[n] ,則 arr[n-1] 不論有沒有取都合法

• 如果有取到 arr[n] ,則一定不能取 arr[n-1]

• f(n,0)=max(f(n-1,0), f(n-1,1))

• f(n,1)=f(n-1,0)+arr[n]

• 最後答案

• max(f(N,0), f(N,1))

參考文獻

相關文件

debug 題:請問右邊這份 code 錯在哪( 題目在此).. What

• 我們通常用 nD/mD 來表示一個狀態 O(N^n) ,轉移 O(N^m) 的 dp 演算法. • 在做每題

• 也就是 ”我的dp是n^3”這句話本身不夠表示你的dp演算法,必須 要說“我的dp是個狀態n^2,轉移n”才夠精確. •

[r]

[r]

• 有一個可以耐重 W 的背包,及 N 種物品,每種物品有各自的重量 w[i] 和價值 v[i] ,且數量為 k[i] 個,求在不超過重量限制的情 況下往背包塞盡量多的東西,總價值最大為多少?.

依賴背包問題 and

creted by howard41436 edited by