动态规划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)

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息