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]);
}
来源:https://www.cnblogs.com/TheRoadToTheGold/p/8387269.html