zoukankan      html  css  js  c++  java
  • 【单调队列优化dp】HDU 3401 Trade

    http://acm.hdu.edu.cn/showproblem.php?pid=3401

    【题意】

    • 知道之后n天的股票买卖价格(api,bpi),以及每天股票买卖数量上限(asi,bsi),问他最多能赚多少钱。开始时有无限本金,要求任两次交易需要间隔W天以上,即第i天交易,第i+w+1天才能再交易。同时他任意时刻最多只能拥有maxp的股票

    【思路】

    • dp[i][j]表示第i天拥有j支股票的最大收益,有三种转移方案:
    • dp[i][j]=max(dp[i][j],dp[i-1][j])表示第i天不买也不卖,由前一天转移而来
    • dp[i][j]=max(dp[i][j],dp[i-w-1][k]-(j-k)*ap[i])表示第i天买股票,有第i-w-1天转移而来
    • dp[i][j]=max(dp[i][j],dp[i-w-1][k]+(k-j)*bp[i])表示第i天卖股票,有第i-w-1天转移而来
    • 注意只需计算由i-w-1天转移而来,因为i-w-1天前的最优值已经通过不买不卖转移到了i-w-1天,即dp[i][j],j固定是随i单调递增的
    • 现在dp的复杂度是n^3,怎样降低复杂度?
    • 分析买股票的情况,dp[i][j]=max(dp[i-w-1][k]+k*ap[i])-j*ap[j],类似a[i]=max(b[k])+c[i],可以用单调队列优化
    • 我理解的是,状态数为2D,转移为1D,然后又有单调性,可以固定一维状态,把转移均摊到另一维,相当于转移是O(1)的,所以单调队列可以把dp降一维
    • a[i]=max(b[k]),若k<=j是从前往后递推,若k>=j是从后往前递推

    【AC】

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=2e3+5;
     5 const int inf=0x3f3f3f3f;
     6 int ap[maxn],bp[maxn],as[maxn],bs[maxn];
     7 int n,maxp,w;
     8 int dp[maxn][maxn];
     9 struct node
    10 {
    11     int x;
    12     int num;
    13 }q[maxn];
    14 int main()
    15 {
    16     int T;
    17     scanf("%d",&T);
    18     while(T--)
    19     {
    20         memset(dp,-inf,sizeof(dp));//求最大值,所以初始化为无穷小 
    21         scanf("%d%d%d",&n,&maxp,&w);
    22         for(int i=1;i<=n;i++) scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
    23         for(int i=1;i<=n;i++) dp[i][0]=0;//拥有股票为0的最大收益当前是0
    24         //前w+1天和[w+2,n]要分开算
    25         //前w+1天只有两种情况:1.每天都不买不卖 2.其中一天买了股票 不能卖股票,而且最多只有一天能交易 
    26         for(int i=1;i<=w+1;i++) 
    27         {
    28             for(int j=1;j<=as[i];j++) 
    29             {
    30                 dp[i][j]=-j*ap[i];//可以选择在当天买 
    31             }
    32         }
    33         for(int j=1;j<=maxp;j++)
    34         {
    35             for(int i=2;i<=w+1;i++)
    36             {
    37                 dp[i][j]=max(dp[i][j],dp[i-1][j]);//也可以选择由前一天转移而来 
    38             }
    39         }
    40         for(int i=w+2;i<=n;i++)
    41         {
    42             int head=1,tail=0;
    43             for(int j=0;j<=maxp;j++)
    44             {
    45                 dp[i][j]=max(dp[i][j],dp[i-1][j]);//不买也不卖
    46                 //dp[i][j]=max(dp[i-w-1][k]+k*ap[i])-j*ap[i],其中k<=j 
    47                 while(head<=tail&&q[tail].x<=dp[i-w-1][j]+j*ap[i]) tail--;
    48                 q[++tail].x=dp[i-w-1][j]+j*ap[i];q[tail].num=j;
    49                 while(q[head].num+as[i]<j) head++;
    50                 dp[i][j]=max(dp[i][j],q[head].x-j*ap[i]);
    51             } 
    52             //dp[i][j]=max(dp[i-w-1][k]+k*bp[i])-j*bp[i],其中k>=j 
    53             head=1,tail=0;
    54             for(int j=maxp;j>=0;j--)
    55             {
    56                 while(head<=tail&&q[tail].x<=dp[i-w-1][j]+j*bp[i]) tail--;
    57                 q[++tail].x=dp[i-w-1][j]+j*bp[i];q[tail].num=j;
    58                 while(q[head].num>bs[i]+j) head++;
    59                 dp[i][j]=max(dp[i][j],q[head].x-j*bp[i]);
    60             } 
    61         }
    62         int ans=0;
    63         for(int i=0;i<=maxp;i++)
    64         {
    65             ans=max(ans,dp[n][i]);    
    66         }
    67         printf("%d
    ",ans);
    68     }
    69     
    70     return 0;
    71 }
    单调队列优化dp
  • 相关阅读:
    小组项目进度汇报
    小组项目进程展示
    结队项目
    小组计划
    个人项目:数独
    问题
    自我介绍
    结对项目
    软件工程基础大项目——数独问题
    关于软件工程的几个问题
  • 原文地址:https://www.cnblogs.com/itcsl/p/7447899.html
Copyright © 2011-2022 走看看