hdu3401

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3401

题意:告诉每天买卖股票的价格,求获得的最大钱。

限制:1.每天买卖的数量限制。AS,BS

    2.股票拥有总量的限制。Maxp

    3.相邻两次买卖股票的天数限制。第i天交易之后,必须等到i+w+1天才能开始交易。

这题的动态规划方程:

1.不买不卖。dp[i][j]=max(dp[i-1][j],dp[i][j]);

2.买一些股票。dp[i][j]=max(dp[i-1][k]-(j-k)*ap[i]);(0<=k<=j<=Maxp)

3.卖一些股票。dp[i][j]=max(dp[i-1][k]+(k-j)*bp[i]);(0<=j<=k<=Maxp)

注意:

初始化问题:

1.把所有未定义的状态都设置为-INF,1~w+1天得初始化,因为这些天不能有前面的状态推出来,初始化为对应购买多少股票所减去的钱数,因为一开始只有买,不能卖。

2.对于每天买卖的数量限制,单调队列要加一个变量来控制是否能从一个状态到另一个状态,而且还是最大的值。

3.循环的递减还是递增问题,跟当前要访问的状态有关。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 2005
#define INF 0xfffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;
int n,Mp,w;
int ap[maxn],bp[maxn],as[maxn],bs[maxn];
struct node
{
    int pos;
    int f;
};
node q[maxn];
int dp[maxn][maxn];
void init()
{
    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<=Mp; j++)
        {
            dp[i][j]=-INF;      //求最大值初始状态都是-INF
        }
    }
    for(int i=1; i<=w+1; i++)      //初始化1~w+1天,这些天只能买,不能卖
    {
        for(int j=0; j<=as[i]; j++)
        {
            dp[i][j]=-ap[i]*j;
        }
    }
    dp[0][0]=0;
}
int main()
{
    int cas,i,j,nowf,head,tail;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d%d%d",&n,&Mp,&w);
        for(i=1; i<=n; i++)
        {
            scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
        }
        init();
        for(i=1; i<=n; i++)
        {
            for(j=0; j<=Mp; j++) //不买不卖
            {
                dp[i][j]=max(dp[i-1][j],dp[i][j]);
            }
            if(i-w-1>=1)
            {
                head=tail=0;
                for(j=0; j<=Mp; j++) //买一些股票,已记录0~j-1
                {
                    nowf=dp[i-w-1][j]+j*ap[i];
                    while(head<tail&&q[tail-1].f<nowf)//注意tail指向下一个位置,找nowf大的第一个数
                        tail--;
                    q[tail].f=nowf;
                    q[tail++].pos=j;
                    while(head<tail&&q[head].pos+as[i]<j)//pos记录数量,数量限制,取数量能够到达j的最大值
                        head++;
                    dp[i][j]=max(dp[i][j],q[head].f-j*ap[i]);
                }
                head=tail=0;
                for(j=Mp; j>=0; j--) //逆序,卖一些股票,已记录j+1~Mp
                {
                    nowf=dp[i-w-1][j]+j*bp[i];
                    while(head<tail&&q[tail-1].f<nowf)
                        tail--;
                    q[tail].f=nowf,q[tail++].pos=j;
                    while(head<tail&&q[head].pos-bs[i]>j)
                        head++;
                    dp[i][j]=max(dp[i][j],q[head].f-j*bp[i]);
                }
            }
        }
        int ans=0;
        for(i=0; i<=Mp; i++)
            ans=max(dp[n][i],ans);
        printf("%d\n",ans);

    }
    return 0;
}


你可能感兴趣的:(hdu3401)