# 動態規劃 DP ## 4/12社課 --- ## 什麼是DP? 用"表格"把運算結果紀錄下來利用 避免重複計算 可分為填表法(Bottom Up) 和遞迴法(Top Down) ---- ## 怎麼用DP? - 拆解題目 把題目分成小部分 - 重複運算(如遞迴)的地方用表格紀錄 - 如果題目給的數字太大記得用long long ---- ### 以DP角度來分析題目 - 定義狀態 - 列轉移式 - 定義初始狀態 ---- ## 狀態 通常指在程式中會變動的參數 題目的每個解都是一種狀態 ---- ## 轉移式 描述每個狀態之間的關聯(如遞迴) 轉移過程可以取用運算過的值求新值 ---- ## 定義初始狀態 就是設定遞迴的初始值 讓遞迴能運作 ---- ## DP複雜度 狀態數*轉移式複雜度 (太複雜的就大概估算就好) --- ## 為什麼需要DP 有紀錄跟沒紀錄運算量其實差很多! 當你TLE的時候就知道~~不能爆搜~~ ---- 舉個例子 以前費氏數列愛用的遞迴 假設需要算出f(100) 就得算出f(99)跟f(98) 如果推算下去 會有3*10²⁰次計算 其中佔最多數的就是重複運算 ##### (數據僅供參考) ---- 這時候DP就派上用場了 把運算結果紀錄後直接取用 就算是f(100000)也只要100000次 ~~好像還是很多~~ ---- 優先運算好的例子(Bottom Up) ```cpp= int dp(100); int main{ int i,num; dp[0]=dp[1]=1; //設初始值 for(i=2;i<100;i++) { dp[i]=dp[i-1]+dp[i-2]; //這裡直接先算好表格裡所有值 } cin >> n; cout << dp[n]; } ``` 也可以利用遞迴(Top Down)減少計算量 ---- ### 填表vs遞迴 大多數時候遞迴會比填表快 只取必要的值 如果題目會重複取值(多狀態)時 因遞迴會重複進函式 所以反而慢一些 --- ## 例題 ---- 假設有n階樓梯 一次可以走1階或2階 總共幾種方法? ---- 如果總方法數是f(n) 那走1階還會有n-1階 f(n-1)種方法 走2階則有f(n-2)種方法 所以總方法數是f(n)=f(n-1)+f(n-2)種 ---- ```cpp= long long dp[1000005]; int f(int n){ if(n<2) return 1; else{ if(dp[n]!=-1) return dp[n];//檢查dp[n]有沒有被計算過 dp[n]=f(n-1)+f(n-2);//算出dp[n]後存入表格 return dp[n]; } } int main{ int a; dp[1000005]={-1}; //如果是-1代表沒算過 while(cin >> a){ cout << f(n); } } ``` ---- 如果題目給的參數有兩個怎麼辦? - 把dp矩陣變成二維的 - 遞迴參數也改成兩個 ---- 回顧一下之前[社課](https://hackmd.io/@Alvin70812/dp#/2/4)的[骰子問題一](https://cses.fi/problemset/task/1633) 其實跟上面的樓梯問題很像 只是f(n)=f(n-1)+...+f(n-6) ---- 這題[骰子問題二](https://cses.fi/problemset/task/1725) 則是把參數變成兩個 f(投擲次數)(數字和)=1/6f(投擲次數-1)(數字和-k) k是指骰子投到的數字 利用遞迴把答案算出來 ---- 上面兩題已經有程式碼 所以就不再打一遍 ~~不是因為我懶~~ ---- [D038](https://zerojudge.tw/ShowProblem?problemid=d038) 這題也是費氏數列 ---- 牆壁長度為n n=1時有1種 n=2時有2種 長度為n時 會有f(n-2)+f(n-1)種 (n-2)的狀態補2塊磚塊 (n-1)的狀態補1塊直立磚塊 ---- ```cpp= #include <iostream> using namespace std; int main(int argc, char** argv) { int dp[52]={0,1,2}; int n; for(int i=3;i<=50;i++){ dp[i]=dp[i-1]+dp[i-2]; } while(cin>>n){ if(n==0)break; cout<<dp[n]<<"\n"; } return 0; } ``` --- ### 練習 [換零錢(d119)](https://zerojudge.tw/ShowProblem?problemid=d119) ---- 補充連結 [stringstream](https://hackmd.io/@Maxlight/rJwlvj8ad)
{"title":"DP","contributors":"[{\"id\":\"f73e3593-2b30-4cf8-89e6-dc544aaab97d\",\"add\":2594,\"del\":272}]"}
    139 views