• P1776 宝物筛选(多重背包)


    Miku

    多重背包板子

    纯多重背包好想>(dp[i]=max{dp[i-k*w[j]]+k*v[j]})

    但是要优化。这里采用二进制优化。

    二进制优化是啥呢,假如i物品有13个

    13可以拆成1+2+4+6,然后用这四个,就可以表示除1-13所有可能了

    这样就把多重背包优化成了01背包

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n,m;
    int w[100001];
    int v[100001];
    int dp[100001];
    int x,y,z;
    int cnt;
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		scanf("%d%d%d",&x,&y,&z);
    		for(int j=1;j<=z;j=j<<1){
    			cnt++;
    			w[cnt]=y*j;
    			v[cnt]=x*j;
    			z-=j;
    		}
    		if(z){
    			cnt++;
    			w[cnt]=z*y;
    			v[cnt]=z*x;
    		}
    	}
    	for(int i=1;i<=cnt;++i){
    		for(int j=m;j>=w[i];--j){
    			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    		}
    	}
    	cout<<dp[m];
    	return 0;
    }
    

    ---------------、
    再来个单调队列的

    单调队列不好理解,最麻烦的事状态转移方程的转化

    原来是(f_j=max{f_{j-k*v} +k*w})

    把j换成a*w+d则
    (f_j=max{f_{a*w+d-k*v} +k*w})

    然后再改变一下(f_j=max{f_{a*w+d-k*v} +k*w-a*w}+a*w)
    就是(f_j=max{f_{(a-k)*v+d} -(a-k)*w}+a*w)

    哇哦,a-k出现了两边,并且如果我们按照%v的余数来分组。a-k就是在新分的组中的编号

    然后就可以用单调队列解决了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int m,n,ans;
    deque <int> q,q2;
    int dp[40010];
    int w,v,c,k;
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		
    //		cout<<endl;
    		scanf("%d%d%d",&w,&v,&c);
    		if(v==0){//单调队列专属特判 
    			ans+=w*c;
    			continue;
    		}
    		k=m/v;
    		c=min(c,k);//能放的最多的 
    		for(int j=0;j<v;++j){//按照余数处理 
    			while(!q.empty()){//先清空 
    				q.pop_back();
    				q2.pop_back();
    			}
    			k=(m-j)/v;//能放多少呢 
    			for(int z=0;z<=k;++z){
    				while(!q.empty()&&dp[j+z*v]-z*w>=q2.back()){//单调队列 部分 
    				//原来的此处极有可能是由上一个物品转移的
    				//所以说-z*w,即是减去当前放的当前物品进行比较
    				//因为最后还是要加的,就像下面 
    					q2.pop_back();
    					q.pop_back();
    				}
    				q.push_back(z);
    				q2.push_back(dp[j+z*v]-z*w);//可转移 
    				while(!q.empty()&&q.front()<z-c){//处理对头 
    					q2.pop_front();
    					q.pop_front();
    				}
    				dp[j+z*v]=max(dp[j+z*v],q2.front()+z*w);
    			}
    		}
    	}
    	cout<<ans+dp[m];
    	return 0;
    }
    
  • 相关阅读:
    Redis数据结构
    PostgreSQL中的onflict
    Lombok注解
    Kafka基本介绍
    Java8特性
    Java8特性Lambda表达式
    网络经济与企业管理(第10章:供应链管理)
    网络经济与企业管理(第9章:企业知识管理)
    网络经济与企业管理(第8章:人力资源管理)
    网络经济与企业管理(第7章:企业财务管理)
  • 原文地址:https://www.cnblogs.com/For-Miku/p/13427449.html
Copyright © 2020-2023  润新知