【HDU 3401】Trade---单调队列优化动归

题目在这里 http://acm.hdu.edu.cn/showproblem.php?pid=3401

 

很明显的动态规划,每一天都有三种情况,不买不卖,买或者卖

状态转移方程是:

对于买

f[i][j] = max (f[i][j], f[r][k] - (j - k) * ap[i]) 1 <= r <= i - w -1 , max(0, j - as[i]) <= k < j

对于卖

f[i][j] = max (f[i][j], f[r][k] + (j - k) * ap[i]) 1 <= r <= i - w -1 , min(maxp, j + bs[i]) >k > j

 总的时间复杂度是0(maxp*maxp*T*T),一定要超时,要降低复杂度

 

优化思想:

 

首先对于每一天,枚举下j做一次

f[i][j] = max(f[i][j],f[i-1][j])

这样就可以保证对于f[i][j],f[i-w-1][]已经包含了前面的最好情况

不用再枚举上次交易是哪一天 1 <= k <= i - w -1这一维了

时间复杂度便成为0(maxp*maxp*T),不过还是不行

 

然后转移的时候:(只讨论买的情况)

f[i-1][r]-(j-r)*ap[i]

即 f[i-1][r]-j*ap[i]+r*ap[i]

外层循环 i,j 必要

则i j确定 ==> j*ap[i] 确定

最优的是f[i-1][r]+r*ap[i]最优

每次i,j循环都要计算但是我们可以把每个r对应的值算出来维护个单调队列

 

对于卖的情况是反序维护,具体见代码

单调队列优化动态规划
  1 /**
  2 *Author : Zhou Hang
  3 *Data    : 2012-5-30
  4 *Prob    : trade
  5 *Sol    : dp with queue
  6 */
  7 
  8 #include <cstdio>
  9 #include <string>
 10 #include <cstring>
 11 #include <algorithm>
 12 
 13 #define MaxN 2100
 14 
 15 using namespace std;
 16 
 17 struct node  
 18 {  
 19     int num, val;  
 20 }q[MaxN];
 21 
 22 int t,maxp,w;
 23 int f[MaxN][MaxN];
 24 int ap[MaxN],bp[MaxN];
 25 int as[MaxN],bs[MaxN];
 26 
 27 
 28 /* 无优化
 29 void Doit(int t,int maxp,int w)
 30 {
 31     //第i天结束后有j股票最大利润
 32     memset(f,143,sizeof(f));
 33     f[0][0]=0;
 34     for (int i=1; i<=t; i++)
 35      for (int j=0; j<=maxp; j++)
 36      {
 37         //nothing to do
 38         f[i][j]=f[i-1][j];
 39 
 40         //buy
 41         //    k'th day r ==>f[k][r] 
 42         for (int k=0; k<i-w; k++)
 43          for (int r=0; r<=j-as[i]; r++)
 44          {
 45             int num=j-r;
 46             f[i][j]=max( f[i][j],f[k][r]-num*ap[i] );
 47          }
 48 
 49         //sell
 50         //    k'th day r ==>f[k][r]
 51         for (int k=0; k<i-w; k++)
 52          for (int r=j; r<=min(maxp,j+bs[i]); r++)
 53          {
 54             int num=r-j;
 55             f[i][j]=max( f[i][j],f[k][r]+num*bp[i] );
 56          }
 57      }
 58 }
 59 */
 60 
 61 
 62 void Doit(int t,int maxp,int w)
 63 {
 64     memset(f,143,sizeof(f));
 65     
 66     for(int i = 1; i <= w + 1; i++)
 67      for(int j = 0; j <= min(as[i], maxp); j++)
 68          f[i][j] = -ap[i] * j;
 69     f[0][0]=0;
 70 
 71     for (int i=2; i<=t; i++)
 72     {
 73         //nothing to do
 74         for (int j=0; j<=maxp; j++)
 75             f[i][j]=max(f[i][j],f[i-1][j]);
 76 
 77         if (i<w+2) continue;
 78         
 79         //buy
 80         int head=1,tail=1;
 81         q[1].num=0; q[1].val=f[i-w-1][0];
 82         
 83         for (int j=1; j<=maxp; j++)
 84         {
 85             //因为j递增 j - q[head].num > as[i] 之后的j也同样 
 86             while (head<=tail && j-q[head].num>as[i])
 87                 head++;
 88             if (head<=tail) f[i][j]=max(f[i][j], q[head].val-(j-q[head].num)*ap[i]); 
 89             while(tail>=head && q[tail].val+(q[tail].num-j)*ap[i]<f[i-w-1][j])
 90                 tail--;
 91             q[++tail].num = j;  
 92             q[tail].val = f[i- w - 1][j];
 93         }
 94         
 95         //sell
 96         head=tail=1;
 97         q[1].num=maxp; q[1].val=f[i-w-1][maxp];
 98         for (int j = maxp - 1; j >= 0; j--)  
 99         {  
100             while(tail >= head && q[head].num - j > bs[i])
101                 head++;  
102             if(head<=tail)  f[i][j]=max(f[i][j],q[head].val+(q[head].num-j)*bp[i]);  
103             while(tail>=head && q[tail].val+(q[tail].num-j)*bp[i]<f[i - w - 1][j]) 
104                 tail--;  
105             q[++tail].num = j;  
106             q[tail].val = f[i - w - 1][j];  
107         }
108     }
109 
110     int rmax=0;
111     for(int i = 0; i <= maxp; i++)
112      if(f[t][i] > rmax) rmax = f[t][i];
113     printf("%d\n", rmax);
114     
115 }
116 
117 int main()
118 {
119     freopen("trade.in","r",stdin);
120     freopen("trade.out","w",stdout);
121     
122     int T;
123     scanf("%d",&T);
124     //case number
125     for (int times=1; times<=T; times++)
126     {
127         scanf("%d%d%d",&t,&maxp,&w);
128         for (int i=1; i<=t; i++)
129         {
130             scanf("%d%d",&ap[i],&bp[i]);
131             scanf("%d%d",&as[i],&bs[i]);
132         }
133         Doit(t,maxp,w);
134 
135         
136     }        
137     
138     
139     fclose(stdin); fclose(stdout);
140     return 0;
141 }

 

 

单调队列优化动归在我看来更多的就是避免重复计算用的,在思考上难度并不是很大,希望以后见到了能做出来吧

转载于:https://www.cnblogs.com/nevergoback/archive/2012/06/01/2530051.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值