動態規劃3 序列型動態規劃

 

序列型動態規劃

 

動態規劃dp[i]中的下標i表示前i個元素a[0],a[1],...,a[i-1]的某種性質算法

初始化中,dp[0]表示空序列的性質數組

座標型動態規劃的初始條件dp[0]就是指以a[0]爲結尾的自子序列的性質spa

 

題目1:LintCode 516 Paint House II

dp[i][1]....dp[i][k]  :尤爲前i棟房子 而且i-1是顏色1~k  的最小花費code

dp[i][1] = min{dp[i-1][2]+cost[i-1][1],.....,dp[i-1][k]+cost[i-1][1]}blog

dp[i][2] = min{dp[i-1][1]+cost[i-1][2],.....,dp[i-1][k]+cost[i-1][2]}排序

...ip

dp[i][k] = min{dp[i-1][1]+cost[i-1][k],.....,dp[i-1][k-1]+cost[i-1][k]}get

 

dp[i][j] = min k≠j {dp[i-1][k]} + cost[i-1][j];it

 

i從0到Nio

j從1到k

k從1到k

算法的時間複雜度:O(NK^2)

加快計算:

dp[i][j] = min k≠j {dp[i-1][k]} + cost[i-1][j];

min k≠j {dp[i-1][k]} :每次須要求f[i-1][1],...,f[i-1][k]中出了一個元素以外其餘元素的最小值

重複計算

抽象:求出除了一個元素的以外的序列中的最小值

好比序列:95 88 75 98 90

75<88<90<95<95

最小值、最小值

在線維護最小值、次小值,就兩個值。

假如最小值dp[i-1][a],次小值爲dp[i-1][b]

則對於j=1,2,3,...,a-1,a+1,...,k   dp[i][j] = dp[i][a]+cost[i-1][j];

dp[i][a] = dp[i-1][b] + cost[i-1][a];

今後時間複雜度就降維O(NK)

 

 1 class Solution {  2 public:  3     /**  4  * @param costs: n x k cost matrix  5  * @return: an integer, the minimum cost to paint all houses  6      */
 7     int minCostII(vector<vector<int>> &A) {  8         // write your code here
 9         int n = A.size(); 10         if(n==0) 11             return 0; 12         
13         const int INF = 0x3f3f3f3f; 14         
15         int k = A[0].size(); 16         
17         int dp[n+1][k];  // 注意數組申請
18         int min1, min2; 19         int j1, j2; 20         
21         // 初始化
22         for(int j=0; j<k; j++){  // dp數組第一列初始化爲0
23             dp[0][j] = 0; 24  } 25         
26         // 從1開始 第一個房子 到 第n個房子
27         for(int i=1; i<=n; i++){ 28             
29             // 求最小值和次小值 每一次都要求
30             min1 = min2 = INF; 31             for(int j=0; j<k; j++){ 32                 if(dp[i-1][j] < min1){ 33                     // 把最小值給次小值
34                     min2 = min1; 35                     j2 = j1; 36                     min1 = dp[i-1][j]; 37                     j1 = j; 38                 }else{  // 這裏也能夠用else if
39                     if(dp[i-1][j] < min2){ 40                         min2 = dp[i-1][j]; 41                         j2 = j; 42  } 43  } 44  } 45             
46             // dp計算
47             for(int j=0; j<k; j++){ 48                 if(j != j1){ 49                     dp[i][j] = dp[i-1][j1] + A[i-1][j]; 50                 }else{ 51                     // j == j1
52                     dp[i][j] = dp[i-1][j2] + A[i-1][j]; 53  } 54  } 55  } 56         
57         int res = INF; 58         for(int j=0; j<k; j++){ 59             res = min(res, dp[n][j]); 60  } 61         
62         return res; 63         
64  } 65 };

 

 

題目2:392 House Robber

https://www.lintcode.com/problem/house-robber/description

不能偷挨着的兩家鄰居

肯定狀態:

最後一個房子 偷 或者 不偷

偷n-1房子:須要知道前n-1棟房子中最大能偷多少金幣

不偷n-1房子:前n-1房子的最優策略

(兩種狀態)

dp[i][0]  不偷

dp[i][1] 偷

  • dp[i][0] = max {dp[i-1][0], dp[i-1][1]}
  • dp[i][1] = dp[i-1][0] + A[i-1]   偷i,只能選擇不偷i-1

---------------------------------------------------------------------------------------------

簡化:在不偷房子i-1的前提下,前i棟房子中最大能偷度多少金幣,其實就是前i-1棟房子能投多少金幣

dp[i] 爲竊賊在前i棟房子最多能投多少金幣。

dp[i] = max {dp[i-1], dp[i-2]+A[i-1]}

 

初始條件:dp[0] = 0 沒房子,偷0枚金幣    序列性動態規劃0就是空

dp[1] = A[0]

dp[2] = max{A[0],A[1]}

 1 class Solution {  2 public:  3     /**  4  * @param A: An array of non-negative integers  5  * @return: The maximum amount of money you can rob tonight  6      */
 7     long long houseRobber(vector<int> &A) {  8         // write your code here
 9         int n = A.size(); 10         if(n==0){ 11             return 0; 12  } 13         long dp[n+1]; 14         dp[0] = 0; 15         dp[1] = A[0]; 16         for(int i=2; i<=n; i++){ 17             dp[i] = max(dp[i-1], dp[i-2]+A[i-1]); 18  } 19         
20         return dp[n]; 21         
22  } 23 };

 

 

題目3:LintCode 534 House Robber || 

https://www.lintcode.com/problem/house-robber-ii/description

上題的房子換成了圈,房子0和房子n-1變成鄰居,不能同時偷盜。

分狀況討論

狀況1:沒偷檔子0       最優策略就是竊賊對於房子1~N-1的最優策略->化爲House Robber

狀況2:沒偷檔子n-1    最優策略就是竊賊對於房子0~N-2的最優策略->化爲House Robber

 

 1 class Solution {  2 public:  3     /**  4  * @param nums: An array of non-negative integers.  5  * @return: The maximum amount of money you can rob tonight  6      */
 7     
 8     int dp_hr(int A[], int n){  9         int dp[n+1]; 10         dp[0] = 0; 11         dp[1] = A[0]; 12         for(int i=2; i<=n; i++){ 13             dp[i] = max(dp[i-1], dp[i-2]+A[i-1]); 14  } 15         return dp[n]; 16  } 17     
18     int houseRobber2(vector<int> &A) { 19         // write your code here
20         
21         int n = A.size(); 22         if(n==0){ 23             return 0; 24  } 25         
26         if(n==1){  // 注意下面切分數組的時候考慮當數組長度爲1,是切分不到東西的。
27             return A[0]; 28  } 29         
30         int A_0[n-1]; 31         for(int i=0; i<n-1; i++){ 32             A_0[i] = A[i]; 33  } 34         
35         int ans = dp_hr(A_0, n-1); 36         
37         
38         
39         int A_1[n-1]; 40         for(int i=1; i<n; i++){ 41             A_1[i-1] = A[i];  // 注意這邊減一
42  } 43         ans = max(ans, dp_hr(A_1, n-1)); 44         
45         return ans; 46  } 47 };

 

 

 

題目4:LintCode 149 Best Time To Buy And Sell Stock

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock/description

[3,2,3,1,2]

2買入3賣出

先買後買

保底策略:

 

 1 class Solution {  2 public:  3     /**  4  * @param prices: Given an integer array  5  * @return: Maximum profit  6      */
 7     int maxProfit(vector<int> &A) {  8         // write your code here
 9         
10         int min_a = A[0]; 11         int ans = 0; 12         for(int i=0; i<A.size(); i++){ 13             int temp = A[i]; 14             if(temp-min_a > ans){ 15                 ans = temp-min_a; 16  } 17             min_a = min(min_a, temp); 18  } 19         return ans; 20  } 21 };

 

 

題目5:LintCode 150 Best Time To Buy And Sell Stock ||

任意屢次買賣,可是任意時刻手中醉倒持有一股。

解法:貪心

買賣一個上升策略

 

 1 class Solution {  2 public:  3     /**  4  * @param prices: Given an integer array  5  * @return: Maximum profit  6      */
 7     int maxProfit(vector<int> &a) {  8         // write your code here
 9         
10         int sum = 0; 11         int per_satrt = 0, index =0; 12         int per_end = 0; 13         if(a.size()==0){ 14             return 0; 15  } 16         // 貪心策略 17         // if(a.size() < 2){ 18         // return 0; 19         // }else if(a.size() == 2){ 20         // if(a[0] < a[1]){ 21         // return a[1]-a[0]; 22         // }else{ 23         // return 0; 24         // } 25         // }
26         for(int  i=1; i<a.size(); i++){ 27             if(a[i] >= a[i-1]){ 28                 per_end = i; 29             }else{ 30                 sum = sum + (a[per_end] - a[per_satrt]); 31                 // 清空變量 要否則會多加
32                 per_satrt = i; 33                 per_end = i; 34  } 35  } 36         sum = sum + (a[per_end] - a[per_satrt]); 37         
38         return sum; 39  } 40 };

 

其實只要記錄相鄰兩天的差值大於0就可,就能夠獲得上升子序列的全部和。

 

 1 class Solution {  2 public:  3     /**  4  * @param prices: Given an integer array  5  * @return: Maximum profit  6      */
 7     int maxProfit(vector<int> &a) {  8         // write your code here
 9         
10         if(a.size() == 0){ 11             return 0; 12  } 13         
14         int res = 0; 15         
16         for(int i=0; i<a.size()-1; i++){ 17             if(a[i+1]-a[i] > 0){ 18                 res += a[i+1]-a[i]; 19  } 20  } 21         
22         return res; 23  } 24 };

 

 

 

題目5:LintCode 150 Best Time To Buy And Sell Stock |||

https://www.lintcode.com/problem/best-time-to-buy-and-sell-stock-iii/description

醉倒兩次買了 兩次賣,每次都是一隻股

  • 買過
  • 沒買過
  • 買多少次

 

把買賣股票的過程劃分:

階段1   第一次買 階段2  第一次賣  階段3  第二次買 階段4  第二次賣 階段5

 

當股票在階段5的時候就不能買了,階段三是能夠買賣依次,階段四繼續持有

 

dp[i][j]: 前i天結束後,在階段j的最大獲利。

階段1,3,5 ---- 手中無股票

dp[i][j] = max{dp[i-1][j], dp[i-1][j-1]+p_i-1-p_i-2}

昨天沒有持有股票             昨天持有股票,今天賣出清倉

 

階段2,4   ---- 手中有股票

dp[i][j] = max{dp[i-1][j]+p_i-1-p_i-2, dp[i][j], dp[i-1][j-1]+p_i-1-p_i-2}

昨天就持有股票,繼續持有並獲利                昨天沒有持有股票,今天買入              昨天持有上一次買的股票,今天買入並當即買入

 

 

 

 

模擬的過程:求序列的上升最大值,而後給每一個子序列排序,選出2個值,這個過程的時間複雜度是O(NlongN)

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息