动态规划(DP)-01背包问题

01背包问题:
有n件物品,每件物品的重量为w[j],价值为c[j]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大。其中每种物品都只有一件。

先采用暴力枚举解决此问题

解题思路:
①每一件物品放或者不放进背包(两种选择)
②若选择此物品,背包的容量V,和总价值W都要随之变化,返回选与不选的物品中价值最大值,否则,V,W都不需要变化
③注意临界条件:选择的物品总体积不可以超过总的体积,注意i的值

Code:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N,M;
struct T{
	int v,w;//物体的体积  物体的价值 
};
vector<T>arr;
int f(int i,int j){//i:个数 j:体积  对第i个物体记性决策 当前已使用的体积为j 
	if(i==N)//边界条件 个数到达了规定的个数 
		return 0; 
	if(arr[i].v+j>M)//背包内已有的体积 +当前物体的体积>规定的背包体积
		return f(i+1,j);//不选这个 继续往后走
	//背包内已有的体积 +当前物体的体积≤规定的背包体积
	return max(f(i+1,j),f(i+1,j+arr[i].v)+arr[i].w);//不选当前物体 个数加一 体积不变 价值也不变 
										//选当前物体 个数加一 体积加上当前物体体积 价值加上当前物体价值 
	 
		
}
int main(){
	cin>>N>>M;//物品的个数  背包的体积 
	arr.resize(N);
	for(int i=0;i<N;i++){
		int a,b;
		cin>>a>>b;
		arr[i].v=a;
		arr[i].w=b;
	}
	cout<<f(0,0);
	return 0;
}
//测试数据:
//4 5
//1 2
//2 4
//3 4
//4 5 

在这里插入图片描述
****显然每件物品都有两种选择,因此n件物品就有 2 n 2^{n} 2n种情况,显然O( 2 n 2^{n} 2n)的复杂度是很糟糕的,而使用动态规划方法可以将复杂度降为O(nV)。

动态规划解决此问题:
在这里插入图片描述

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N,M;
struct T{
	int v,w;//物体的体积  物体的价值 
};
vector<T>arr;
vector<vector<int>>dp; 
void fdp(){
	for(int i=N-1;i>=0;i--){//从后往前推导 
		for(int j=0;j<=M;j++){
			if(j+arr[i].v>M)//超出规定的体积 
				dp[i][j]=dp[i+1][j];//根据暴力枚举中这个 if(arr[i].v+j>M) return f(i+1,j); 式子得来 
			else
				dp[i][j]=max(dp[i+1][j],dp[i+1][j+arr[i].v]+arr[i].w);
				//根据暴力枚举中 max(f(i+1,j),f(i+1,j+arr[i].v)+arr[i].w); 这个式子得来 
		}
	}
	cout<<dp[0][0];
}
int main(){
	cin>>N>>M;//物品的个数  背包的体积 
	arr.resize(N+1);//注意需要赋值为N+1 在第19行 i初始值为N-1  加一之后下标为N 
	dp.resize(N+1);
	for(int i=0;i<=N;i++)
		dp[i].resize(M+1);
		
	for(int i=0;i<=N;i++)//为了保证最后一行是0 
		for(int j=0;j<=M;j++)
			dp[i][j]=0;		
	for(int i=0;i<N;i++){
		int a,b;
		cin>>a>>b;
		arr[i].v=a;
		arr[i].w=b;
	}
	fdp();
	return 0;
}
//测试数据:
//4 5
//1 2
//2 4
//3 4
//4 5 

进一步节省空间:一维数组

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N,M;
struct T{
	int v,w;//物体的体积  物体的价值 
};
vector<T>arr;
vector<int>dp; 
void fdp(){
	for(int i=0;i<N;i++)//从左往右推导 
		for(int j=0;j<=M-arr[i].v;j++)//控制背包内的物品体积不能超过背包的最大可容纳的体积 
				dp[j]=max(dp[j],dp[j+arr[i].v]+arr[i].w);
				 
	cout<<dp[0];
}
int main(){
	cin>>N>>M;//物品的个数  背包的体积 
	arr.resize(N);
	dp.resize(N+1);
	for(int i=0;i<N;i++)
			dp[i]=0;		
	for(int i=0;i<N;i++){
		int a,b;
		cin>>a>>b;
		arr[i].v=a;
		arr[i].w=b;
	}
	fdp();
	return 0;
}
//测试数据:
//4 5
//1 2
//2 4
//3 4
//4 5 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值