hdu2191多重背包单调队列优化

多重背包单调队列优化:

dp[c+i*p]=max(dp[c+k*p]+(i-k)*h);

每种背包的容量p,价值h,c的范围为0~p-1,i和k的范围为0~num(能够取的背包的数量)

背包的取法可以看做是划分为0~p-1这p个容量再加上i个背包。

dp[c+i*p]=dp[c+k*p]-k*h+i*h;

代码:

#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<cstdio>
#include<cstring>
#define maxn 2000
#define INF 0xfffffff
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;
struct node
{
    int f;
    int pos;
};
node q[maxn];
int dp[maxn];
int n,m,p,h,num,head,tail,nowf;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d%d",&n,&m);//总钱数n
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&p,&h,&num);//价格,重量,袋数
            num=min(num,n/p);

            for(int j=0;j<p;j++)//0~p-1种
            {
                head=tail=0;
                for(int k=0;k<=(n-j)/p;k++)
                {
                    nowf=dp[j+p*k]-k*h;
                    while(head<tail&&q[tail-1].f<=nowf)
                    tail--;
                    q[tail].f=nowf,q[tail++].pos=k;
                    while(head<tail&&q[head].pos<k-num)//是否能通过增加num达到k
                    head++;
                    dp[j+k*p]=q[head].f+k*h;
                }
            }
        }
        printf("%d\n",dp[n]);
    }
	return 0;
}


你可能感兴趣的:(hdu2191多重背包单调队列优化)