hdu 3401 单调队列优化动态规划

思路:

动态方程很容易想到dp[i][j]=max(dp[i][j],dp[i-w-1][j-k]-k*ap[i],dp[i-w-1][j+k]+k*bp[i]);

dp[i][j]表示第i天拥有j个石头的最大价值。

其实每次求得都是最有策略,所有dp[i-w-1]表示的就是i-w-1以前的最优,故不同往前遍历。

那么主要需要优化的是:

对于买石头,容量为j时,维护从j-k到j的转移最大值。即从哪个容量转移过来能得到最大效益。

对于卖石头,容量为j时,维护从j+k到j的转移最大值。即从哪个容量转移过来能得到最大效益。

见代码:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cmath>

#define inf 10000010

#define Maxn 2010

#define Min(a,b) (a)>(b)?(b):(a)

using namespace std;

int dp[Maxn][Maxn],as[Maxn],bs[Maxn],ap[Maxn],bp[Maxn];

struct Que{

    int val,pos;

}que[10000];

int main()

{

    int n,t,p,w,i,j,k;

    scanf("%d",&t);

    while(t--)

    {

        scanf("%d%d%d",&n,&p,&w);

        for(i=1;i<=n;i++)

            for(j=0;j<=p;j++)

            dp[i][j]=-inf;//初始化

        for(i=1;i<=n;i++)

            scanf("%d%d%d%d",ap+i,bp+i,as+i,bs+i);

        for(i=1;i<=w+1;i++)//预处理

            for(j=0;j<=as[i];j++)

                dp[i][j]=-j*ap[i];

        for(i=2;i<=n;i++)

        {

            for(j=0;j<=p;j++)

            dp[i][j]=max(dp[i][j],dp[i-1][j]);//预处理

            if(i<=w+1) continue;

            int head=1,rear=0;

            for(j=0;j<=p;j++)//买石头

            {

                while(head<=rear&&(que[rear].val-(j-que[rear].pos)*ap[i])<=dp[i-w-1][j])

                    rear--;

                que[++rear].pos=j,que[rear].val=dp[i-w-1][j];

                if(que[head].pos<j-as[i]) head++;

                dp[i][j]=max(dp[i][j],que[head].val+(que[head].pos-j)*ap[i]);

            }

            head=1,rear=0;

            for(j=p;j>=0;j--)//卖石头

            {

                while(head<=rear&&(que[rear].val+(que[rear].pos-j)*bp[i])<=dp[i-w-1][j])

                    rear--;

                que[++rear].pos=j,que[rear].val=dp[i-w-1][j];

                if(que[head].pos>j+bs[i]) head++;

                dp[i][j]=max(dp[i][j],que[head].val+(que[head].pos-j)*bp[i]);

            }

        }

        int Max=0;

        for(i=0;i<=p;i++)//找出最大效益

            if(dp[n][i]>Max)

            Max=dp[n][i];

        printf("%d\n",Max);

    }

    return 0;

}

 

你可能感兴趣的:(动态规划)