单调队列优化多重背包

别说谁变了你拦得住时间么 提交于 2019-12-20 20:30:02

http://codevs.cn/problem/5429/

 

把背包体积按 模物品体积 分类

在每个剩余类中使用单调队列

 

具体点就是

设物品体积为v,价值为w,现在要计算体积模v=0时的价值

设f[i][j] 表示 前i个物品,体积为j时的最大价值

f[i][5v]=max{ f[i-1][4v]+w , f[i-1][3v]+2w , f[i-1][2v]+3w , f[i-1][v]+4w , f[i-1][0]+5w }

f[i][4v]=max{ f[i-1][3v]+w , f[i-1][2v]+2w , f[i-1][v]+3w , f[i-1][0]+4w }

对所有的f[i][j]-j/v*w

f[i][5v]=max{ f[i-1][4v]-4w , f[i-1][3v]-3w , f[i-1][2v]-2w , f[i-1][v]-w , f[i-1][0] }

f[i][4v]=max{                        f[i-1][3v]-3w , f[i-1][2v]-2w , f[i-1][v]-w , f[i-1][0] }

f[i][j]=max{f[i-1][j%v+k*v]-k*w}+j*w

当固定了j%v后,就可以使用单调队列优化了

 

 

#include<cstdio>

using namespace std;

int dp[7001];

int q[7001][2];

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int v,w,cnt;
    int h,t;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d%d",&v,&w,&cnt);
        if(m/v<cnt) cnt=m/v;
        for(int j=0;j<v;++j)
        {
            h=0; t=0;
            for(int k=0;k<=(m-j)/v;++k)
            {
                while(h<t && dp[j+k*v]-k*w>q[t-1][0]) t--;
                while(h<t && q[h][1]+cnt<k) h++;
                q[t][0]=dp[j+k*v]-k*w;
                q[t++][1]=k;
                dp[j+k*v]=q[h][0]+k*w;
            }
        }
    }
    printf("%d",dp[m]);
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!