zz的01背包问题 基础动态规划题 经典01背包

本文介绍了zz面临的01背包问题,背包容量有限,需要选择零食以获得最大满足度。问题涉及n种零食,每种有占用空间和满足度。通过动态规划解决,给出三种思路:二维数组DP、优化的一维数组DP和记忆化搜索。

题目
zz的01背包问题

描述
zz每天都会去零食店寻找自己喜欢吃的零食。可惜的是zz的背包容量(V<=10000)是有限的,他只能装一定重量的零食。为了买到自己满意度更高的零食组合,zz给每种零食都赋予了一个满足度,表示zz买了这种零食后可以收获的满足度是多少。零食的种类有n(n<=100)种,每种零食都有一个占用空间(Wi<=100),和一个zz的满足度(Di<=1000)。请你帮zz小朋友计算一下,他能得到的最大满足度是多少?

输入格式
第一行包含两个整数n,v,分别表示零食的种类和zz的背包的容量。
接下来n行,每行两个整数Wi和Di,分别表示第i种零食的占用空间和买了这种零食后zz获得的满足度。

输出格式
一行一个整数,表示zz能够获得的最大满足度。

输入样例
6 10
1 4
4 3
5 6
2 2
3 2
5 7

输出样例
14

题目思路

第一种思路 dp二维数组

#include <iostream>
#include <algorithm>
using namespace std;
int dp[101][10001];
int main(){

	int n,v,w[101],d[101]; //定义变量 

	cin>>n>>v; 
	for(int i=1;i<=n;i++) cin>>w[i]>>d[i];//输入 

	for(int i=1;i<=n;i++){
		for(int j=1;j<=v;j++){
			dp[i][j]=dp[i-1][j];
			if(j>=w[i])
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+d[i]); 
				//状态转移方程 
		}
	}

	cout<<dp[n][v]<<endl; //输出 
	return 0;
}

第二种思路 优化成dp一位数组

#include <iostream>
#include <algorithm>
using namespace std;
int dp[10001];
int main(){
int n,v,w[101]={},d[101]={}; //数组定义 

	cin>>n>>v;
	for(int i=1;i<=n;i++) cin>>w[i]>>d[i]; //输入 

	for(int i=1;i<=n;i++){
		for(int j=v;j>=1;j--){
			if(j>=w[i])
				dp[j]=max(dp[j],dp[j-w[i]]+d[i]); //优化状态转移方程 
		}
	}
	cout<<dp[v]<<endl; //输出 
	return 0;
}

第三种思路 记忆化搜索

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int dp[105][3][10005]={};
int n,v;int w[105]={},d[105]={}; //定义变量
int dfs(int step_n,int point_w,int bag_v){

	if(step_n>n||bag_v>v) return 0;
	if(dp[step_n][point_w][bag_v]!=-1) return dp[step_n][point_w][bag_v]; 
	//递归终止条件 
	
	int tmp1=0,tmp2=0;
	if(bag_v+w[step_n]<=v)
	tmp1=dfs(step_n+1,1,bag_v+w[step_n])+d[step_n]; 
	tmp2=dfs(step_n+1,2,bag_v); //递归 
	
	dp[step_n][point_w][bag_v]=max(tmp1,tmp2); //赋值 
	return dp[step_n][point_w][bag_v]; //返回值 
}
int main(){

	cin>>n>>v;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&w[i],&d[i]);
	} //输入
	 
	for(int i=0;i<105;i++){
		for(int j=0;j<3;j++){
			for(int k=0;k<10005;k++){
				dp[i][j][k]=-1;
			}
		}
	} //数组初始化 
	
	cout<<dfs(0,0,0)<<endl; //输出 
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值