• 蒟蒻の背包dp学习总结


    0/1背包

    定义

    01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。

    模板

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;//n表示物品数量,m表示总容积 
    struct node{
    	int w,v;//w表示体积,v表示价值 
    }a[10010];
    int dp[30010];
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i].w>>a[i].v;
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=m;j>=a[i].w;j--){
    			dp[j]=max(dp[j],dp[j-a[i].w]+a[i].v);
    		}
    	}
    	cout<<dp[m];
    	return 0;
    }
    

    例题

    P1048 采药

    思路

    由题意可得,每株草药只可采一次,且给定了总背包容量和每株草药的信息,则可判定该题是0/1背包问题

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int t,m;
    struct node{
    	int time,value;
    }a[110];
    int dp[1010];
    int main(){
    	cin>>t>>m;
    	for(int i=1;i<=m;i++){
    		cin>>a[i].time>>a[i].value;
    	}
    	for(int i=1;i<=m;i++){
    		for(int j=t;j>=a[i].time;j--){
    			dp[j]=max(dp[j],dp[j-a[i].time]+a[i].value);
    		}
    	}
    	cout<<dp[t];
    	return 0;
    }
    

    P1049 装箱问题

    思路

    该题仅给定了每件物品的体积和背包总容量,但是题目中隐晦地告诉我们:价值就是每件物品的体积! ,故此题只需使用0/1背包模板求所占的最大体积,最后输出总体积-求所占的最大体积即可,是一道0/1背包基础变形题

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int a[40];
    int v;
    int dp[20010];
    int main(){
    	cin>>v>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=v;j>=a[i];j--){
    			dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
    		} 
    	}
    	cout<<v-dp[v];
    	return 0;
    }
    

    P1060 开心的金明

    思路

    由题意可得,该题的**每件价值为体积(每件物品所花钱数)* 重要度 **,那么这题就变成了常规的0/1问题,故此题只需仔细读题即可求出答案

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    struct node{
    	int w,v;
    }a[30];
    int dp[30010];
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=m;i++){
    		cin>>a[i].w>>a[i].v;
    		a[i].v*=a[i].w;
    	}
    	for(int i=1;i<=m;i++){
    		for(int j=n;j>=a[i].w;j--){
    			dp[j]=max(dp[j],dp[j-a[i].w]+a[i].v);
    		}
    	}
    	cout<<dp[n];
    	return 0;
    }
    

    完全背包

    定义

    有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

    模板

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;//n表示物品数量,m表示总容积 
    struct node{
    	int w,v;//w表示体积,v表示价值 
    }a[10010];
    int dp[30010];
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i].w>>a[i].v;
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=a[i].w;j<=m;j++){
    			dp[j]=max(dp[j],dp[j-a[i].w]+a[i].v);
    		}
    	}
    	cout<<dp[m];
    	return 0;
    }
    

    例题

    P1616 疯狂的采药

    思路

    由题意可得,每株草药可采无限次,也给定了每株草药的信息和总容积,则该题为一道完全背包题

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int t,m;
    struct node{
    	int v,w;
    }a[10010];
    int dp[10000010];
    int main(){
    	cin>>t>>m;
    	for(int i=1;i<=m;i++){
    		cin>>a[i].w>>a[i].v;
    	}
    	for(int i=1;i<=m;i++){
    		for(int j=a[i].w;j<=t;j++){
    			dp[j]=max(dp[j],dp[j-a[i].w]+a[i].v);
    		}
    	}
    	cout<<dp[t];
    	return 0;
    }
    

    P5662 纪念品

    思路

    **这题题面有一句关键的话,“当日购买的纪念品也可以当日卖出换回金币”!**这句话可以帮我们简化状态,因为如果一个纪念品,你想连续持有若干天,可以看做第一天买,第二天早上立刻卖掉,然后第二天买回来,第三天早上立刻卖掉,然后第三天买回来……所以我们就不需要记录每天手里持有多少纪念品了,统一认为我们今天买的纪念品,明天早上就立刻卖掉。明天又是新的一天,用所有的现金,进行新的决策就好了。

    C o d e Code Code

    #include<bits/stdc++.h>
    using namespace std;
    int t,n,m;
    int a[110][110];
    int dp[10100];
    int main(){
    	cin>>t>>n>>m;
    	for(int i=1;i<=t;i++){
    		for(int j=1;j<=n;j++){
    			cin>>a[i][j];
    		}
    	}
    	for(int i=1;i<=t;i++){
    	    memset(dp,0,sizeof(dp));
    	    for(int j=1;j<=n;j++)  
    	        for(int k=a[i][j];k<=m;k++)
    	            dp[k]=max(dp[k],dp[k-a[i][j]]+a[i+1][j]-a[i][j]);
    	    m=max(dp[m]+m,m);
    	}
    	cout<<m;
    	return 0;
    }
    

    多重背包

    定义

    有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

    模板

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int v[110],w[110],s[110];
    int dp[110];
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>v[i]>>w[i]>>s[i];
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=m;j>=v[i];j--){
    			for(int k=1;k<=s[i]&&k*v[i]<=j;k++){
    				dp[j]=max(dp[j],dp[j-k*v[i]]+k*w[i]);
    			}
    		}
    	}
    	cout<<dp[m];
    	return 0;
    }
    

    例题(没有找到合适的例题qwq)

    她透过我的血,看到了另一抹殷红
  • 相关阅读:
    CF353D Queue(结论)
    CF1147C Thanos Nim(博弈论、结论推导)
    牛客:CBX and children(平衡树+二分+贪心)
    牛客:Gambling Monster(权值线段树+离散化+离线)
    剑指49.把字符串转换成整数
    剑指48.不用加减乘除做加法
    剑指47.求1+2+3+...+n
    剑指46.孩子们的游戏(圆圈中最后剩下的数字)
    剑指45.扑克牌顺子
    剑指44.翻转单词顺序
  • 原文地址:https://www.cnblogs.com/zhangbeini/p/13771242.html
Copyright © 2020-2023  润新知