• 多重背包优化


    题目:

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

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

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

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

    输入格式

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

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

    输出格式

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

    数据范围

    0<N10000<N≤1000
    0<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<bits/stdc++.h>
    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<n;i++){
    		int w,val,num;
    		scanf("%d%d%d",&w,&val,&num);
    		int cnt=min(num,m/w);
    		for(int j=0;j<w;j++){//j为余数 
    			tail=0;
    			head=1;
    			for(int k=0;k<=(m-j)/w;k++){
    				while(head<=tail&&que[head].pos<k-cnt)head++;
    				while(head<=tail&&que[tail].val<=dp[j+k*w]-k*val)tail--;
    				que[++tail].val=dp[j+k*w]-k*val;
    				que[tail].pos=k;
    			//	tail++;
    				dp[j+k*w]=que[head].val+k*val;
    			}	
    		}
    	}
    //	for(int i=0;i<=m;i++)
    	printf("%d",dp[m]);
    	return 0;
    } 
    

      

    #include<bits/stdc++.h>
    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
    ",dp[m]);
    	return 0;
    } 
    

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

     
  • 相关阅读:
    C语言作业9
    C语言作业8
    学习体会
    C语言作业7
    C语言作业6
    C语言作业5
    C语言作业4
    C语言作业3
    丛铭俣 160809324 (作业12)
    丛铭俣 160809324 (作业10)
  • 原文地址:https://www.cnblogs.com/Zhi-71/p/11740330.html
Copyright © 2020-2023  润新知