多重背包单调队列优化

1.朴素多重背包

先枚举每一个物品,再枚举物品个数,最后枚举现在的重量时间复杂度O\left ( \sum n[i]*n*w \right )

for(int i=1;i<=n;i++){
	for(int j=1;j<=n[i];j++){
		for(int k=w;k>=j*w[i];k--){
			dp[k]=max(dp[k],dp[k-j*v[i]]+j*w[i])
		}
	}
} 

2.单调队列优化多重背包

每一个物品更新的时候,更新到体积为n的状态,都是与n于w[i]的模数相等的状态转移而来的,所所以对于每个物品i,都有dp[i*v[i]+j]=max\left ( dp[n*v[i]+j]+(n-i)*w[i] \right )\left ( max(0,i-n[i])\leq n< i\right )

也就是:

dp[i*v[i]+j]=max\left ( dp[n*v[i]+j]-n*w[i] \right )+i*w[i]\left ( max(0,i-n[i])\leq n< i\right ) 

可以将符合条件的dp[n*v[i]+j]-n*w[i]用单调队列维护,每个数都只会进出队列一次,就可以将一维复杂度,为

O(n*\frac{w}{w[i]}*w[i])=O(n*w) 

for(int j=0;j<v[i];j++){
	deque<pair<int,int> >q;
	int gs=(t-j)/v[i];
	for(int k=gs;k>=max(0,gs-n[i]);k--){
		while(!q.empty()&&q.back().first<=dp[k*v[i]+j]-k*w[i]) q.pop_back();
		q.push_back(make_pair(dp[k*v[i]+j]-k*w[i],k));
	}//先将所有符合条件的都存入队列
	int o=gs-n[i];
	for(int k=gs;k>0;k--){
		while(q.front().second>=k) q.pop_front();//不符合条件的弹出
		dp[k*v[i]+j]=max(dp[k*v[i]+j],q.front().first+k*w[i]);
		o--;
		if(o<0) continue;
		while(!q.empty()&&q.back().first<=dp[o*v[i]+j]-o*w[i]) q.pop_back();//没有这个优的弹出
		q.push_back(make_pair(dp[o*v[i]+j]-o*w[i],o));
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值