動態規劃入門(一)
阿新 • • 發佈:2017-09-01
spa turn color and uil ott c++ erro 大數字
2017-09-01 11:29:43
writer:pprp
看sprout臺灣大學acm教學視頻的第一部分:
裏邊涉及到四道小例題
感覺很好就拿來寫了寫:
題意還有代碼說明都在代碼中:
1、最基礎的骨牌問題:
/* @param:dp 入門 @writer:pprp @declare:最經典最簡單的dp @begin:9:00 @end:10:00 @date:2017/9/1 */ #include <bits/stdc++.h> using namespace std; //未優化的最基礎的 int fun(int n) { if(n == 1) return 1; if(n == 2) return 2; return fun(n-1) + fun(n-2); } //自頂向下的記憶化 //top down 小心遞回過深 int dp[101] = {1,1,2}; int fun2(int n) { if(dp[n] != 0) return dp[n]; return fun2(n-1) + fun(n-2); } //自底向上 //子問題一定要比母問題要先跑到,註意遞回跑法 int dp2[101] = {0}; void build() { dp2[1] = 1; dp2[2] = 2; for(int i = 3 ; i < 101; i++) dp2[i] = dp2[i-1] + dp2[i-2]; } int fun3(int n) { return dp2[n]; } int main() { build(); int a; while(cin >> a) { cout << fun(a) << endl; cout << fun2(a) << endl; cout << fun3(a) << endl; } return0; }
2、塗色問題:題意見代碼頭
/* @param:dp 入門 @writer:pprp @declare:最經典最簡單的dp,給紅綠藍三種顏色,讓你求出藍綠不相鄰的排列n個元素的情況 @begin:10:10 @end:10:28 @date:2017/9/1 */ #include <bits/stdc++.h> using namespace std; /* 狀態確定:按照最後一位的顏色確定狀態 f(n,0):最後一位是紅色的數量 f(n,1):最後一位是綠色的數量 f(n,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) 初始條件: f(1,0) = 1; f(1,1) = 1; f(1,2) = 1; 最終答案: f(n,0) + f(n,1) +f(n,2); */ // top down int dp1[101][3] = {0}; void init() { dp1[1][0] = dp1[1][1] = dp1[1][2] = 1; } int fun(int n,int m) { if(dp1[n][m] != 0) return dp1[n][m]; if(m == 0) dp1[n][0] = fun(n-1,0) + fun(n-1,1) + fun(n-1,2); if(m == 1) dp1[n][1] = fun(n-1,0) + fun(n-1,1); if(m == 2) dp1[n][2] = fun(n-1,0) + fun(n-1,2); return dp1[n][m]; } //bottom up int dp2[101][3] = {3}; int build() { dp2[1][0] = dp2[1][1] = dp2[1][2] = 1; for(int i = 2; i < 101 ; i++) { dp2[i][0] = dp2[i-1][0] + dp2[i-1][1] + dp2[i-1][2]; dp2[i][1] = dp2[i-1][0] + dp2[i-1][1]; dp2[i][2] = dp2[i-1][0] + dp2[i-1][2]; } } int fun2(int n) { return dp2[n][0] + dp2[n][1] + dp2[n][2]; } //run int main() { int a; cin >> a; init(); build(); cout << fun(a,0) + fun(a,1) + fun(a,2) << endl; cout << fun2(a) << endl; return 0; }
3、骨牌問題2,加了一個L型骨牌
/* @param:dp 入門 @writer:pprp @declare:最經典最簡單的dp, 給你2*1 & 3*1 L型骨牌填滿2*n的格子,有幾種拍法 @begin:10:36 @end:11:00 @date:2017/9/1 */ #include <bits/stdc++.h> using namespace std; /* 狀態分析: f(n) 代表的是放n*2個格子時候的方法數 狀態轉移: 如果最後那塊放2*1的:f(n) = f(n-1) + f(n-2) 如果最後那塊放3*1的:f(n) = f(n-3) + f(n-4) + ... + f(0),由於對稱的關系,要乘2 綜合起來: f(n) = f(n-1) + f(n-2) + 2 * (f(n-3) + f(n-4) +...+ f(0)) 邊界狀態:f(0) = 1; f(1) = 1; f(2) = 2; */ //top down int dp[101] = {0}; void init() { dp[0] = dp[1] = 1; dp[2] = 2; } int fun(int n) { init(); if(dp[n] != 0) return dp[n]; dp[n] = 2 * fun(n-1) + fun(n-3); return dp[n]; } //bottom up int dp2[101] = {}; void build() { dp2[0] = dp2[1] = 1; dp2[2] = 2; for(int i = 3 ; i < 101 ; i++) dp2[i] = 2 * dp2[i-1] + dp2[i-3]; } int fun2(int n) { return dp2[n]; } int main() { int a; srand((int)time(NULL)); a = rand()%100; build(); cout << fun(a) << endl; cout << fun2(a) << endl; return 0; }
4.找到不相鄰的數的最大和
/* @param:dp 入門 @writer:pprp @declare:最經典最簡單的dp,給你一個正整數陣列, 從裏邊取出不相鄰的數,問你取出數字和最大為多少? @begin:1:05 @end:11:25 @error:應該是從1開始不是從0開始 @date:2017/9/1 */ #include <bits/stdc++.h> using namespace std; /* 狀態分析: f(n)代表的是當前取了這個位置以後的最大數字和 狀態轉移: f(n) = max(f(n-2),f(n-3) + arr[n]; 邊界狀態:f(0) = 0, f(1) = arr[1], f[2] = max(arr[1],arr[2]) */ //top down int arr[101] = {}; int dp[110] = {}; void init() { dp[0] = 0; dp[1] = arr[1]; dp[2] = max(arr[1],arr[2]); dp[3] = max(arr[1]+arr[3],arr[2]); } int fun(int n) { init(); if(dp[n] != 0) return dp[n]; dp[n] = max(fun(n-2),fun(n-3)) + arr[n]; return dp[n]; } int dp2[110] = {}; //bottom up void build() { dp2[0] = 0; dp2[1] = arr[1]; dp2[2] = max(arr[1],arr[2]); for(int i = 3; i < 101 ; i++) { dp2[i] = max(dp2[i-2],dp2[i-3]) + arr[i]; } } int fun2(int n) { return dp2[n]; } int main() { freopen("in.txt","r",stdin); int n; cin >> n; for(int i = 1 ; i <= n ; i++) cin >> arr[i]; init(); build(); cout << max(fun(4),fun(5)) << endl; cout << max(fun2(4),fun2(5)) << endl; return 0; }
總結:
狀態確定很重要,利用對稱的關系分析可以簡化,
動態規劃是一個走一步算一步的算法過程,不要全局的去分析,否則越分析越亂,按照每一步的走向來確定狀態轉移方程
做的多了動態規劃才能有靈感
動態規劃入門(一)