多重背包优化

题目:

https://www.acwing.com/problem/content/6/

有 N 种物品和一个容量是 V 的背包。

第 ii 种物品最多有 si 件,每件体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式

第一行两个整数,N,V (0<N1000(00<V20000),用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i种物品的体积、价值和数量。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N100000<V200000
0<vi,wi,si200000

提示

本题考查多重背包的单调队列优化方法。

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

发现每种物品数量足够多直接做完全背包肯定会超时,在此介绍两种优化的方法。
二进制优化:
我们可以把某些物品看成一个新的物品,就比如有10个重量为1,价值为2的物品,那么我们可以把它们拆成重量为1,价值为2;重量为2,价值为4;重量为4,价值为8;重量为3,价值为6四种物品,然后做0-1背包就行了,这样也可以枚举取0-10个的所有情况。
这样时间复杂度就成n*m*log(w)了。值得注意的是:当某个数量w与价值val的积大于等于背包总容量m(即w*val>=m)时可以看成完全背包。
单调队列:时间复杂度为n*m
这个还是推荐一篇博客供参考吧(QAQ):https://www.cnblogs.com/-guz/p/9866118.html
#include
using namespace std;
int dp[20005];
struct st{
	int val,pos;
}que[20005];
int tail;
int head;
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i 
 

  

#include
using namespace  std;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll dp[20005];
int main(){
	int n,m;
	int w,v,num;
	scanf("%d%d",&n,&m);
	while(n--){
		scanf("%d%d%d",&w,&v,&num);
		if(w*num>=m){
			for(int i=w;i<=m;i++){
				dp[i]=max(dp[i],dp[i-w]+v);
			}
		}
		else{
			int w1,v1;
			int cnt=1;
			while(num>=cnt){
				num-=cnt;
				
				w1=cnt*w;
				v1=cnt*v;
				for(int i=m;i>=w1;i--){
					dp[i]=max(dp[i],dp[i-w1]+v1);
				}
				cnt*=2;
			}
			if(num>0){
				w1=num*w;
				v1=num*v;
				for(int i=m;i>=w1;i--){
					dp[i]=max(dp[i],dp[i-w1]+v1);
				}
			}
		}
	}
	printf("%lld\n",dp[m]);
	return 0;
} 

  (第二种竟然比一种还快。。。。)

 

你可能感兴趣的:(多重背包优化)