蒟蒻の背包dp学习总结

17 篇文章 0 订阅
3 篇文章 0 订阅

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)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值