01背包问题

题目传送门

有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。

第 ii 件物品的体积是 vivi,价值是 wiwi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000

输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
题解:

这是一道典型的DP问题,背包问题,找到动态转移方程就可做了,那动态转移方程式怎么样的呢。

为了方便理解,设置一些变量

设weight[i]为物的品重量

设value[i]为物品的价值

设dp(i,j)为存储第i件物品是,当前背包j重量的价值

动态转移方程:
1.当j=0,dp(i,j)为0

​ 1.1背包容量j为0时,背包价值为0

2.当j>0时,有两种情况

​ 2.1当j>=weight[i],表示当前背包容量大于第i件物品重量,可以放得下

​ 2.1.1.放得下(j>=weight[i]),但是这个物品并性价不高,所以dp(i,j)=dp(i-1,j)

​ 2.1.2.放得下(j<weight[i]),这个物品性价比高,所以dp(i,j)=dp(i-1,j-weight[i])

​ 注:(dp(i-1,j-weight[i])表示为了放下这个物品,需要腾出weight[i]的重量那么大的空间)

​ 所以最终结果看那个性价比高,最终动态转移方程为dp(i,j)=max(dp(i-1,j),dp(i-1,j-weight[i]))

​ 2.2.当j<weight[i],表示当前背包容量小于第i件物品重量,放不下

​ 放不下的话,那么dp(i,j)=dp(i-1,j)

核心代码:

for(int i=1;i<=n;i++){//外层循环,n为物品件数
			for(int j=1;j<=v;j++){//内层循环,v为背包质量 
				if(j>=weight[i])//放得下 
					dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
				else//放不下 
					dp[i][j]=dp[i-1][j];
			}
		}

AC代码:

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int weight[1010],value[1010],dp[1010][1010];
int main(){
	int n,v;
	while(cin>>n>>v){
		for(int i=1;i<=n;i++) {
			cin>>weight[i]>>value[i];
		}
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++){//外层循环,n为物品件数
			for(int j=1;j<=v;j++){//内层循环,v为背包质量 
				if(j>=weight[i])//放得下 
					dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
				else//放不下 
					dp[i][j]=dp[i-1][j];
			}
		}
		cout<<dp[n][v]<<endl;
	}
	return 0;
} 
优化版本:

一般版本都是二维数组,当数据量比较大的时候,对内层空间是一个很大的挑战,所以现在用“滚动数组”进行优化,就是用一维数组重复使用,但并不影响结果,先上代码。

核心代码:

for(int i=1;i<=n;i++){//外层循环,n为物品件数
			for(int j=v;j>=1;j--){//内层循环从v到1,v为背包质量
				if(j>=weight[i])//放得下 
					dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
				else//放不下 
					dp[j]=dp[j];
			}
		}

dp从二维数组变成了一维,但并不影响结果,之前的二维数组的内层循环j是从1到v,现在是v到1,这样从后往前就达到了dp(i,j)=max(dp(i-1,j),dp(i-1,j-weight[i]))

AC代码:

#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int weight[1010],value[1010],dp[1010];
int main(){
	int n,v;
	while(cin>>n>>v){
		for(int i=1;i<=n;i++) {
			cin>>weight[i]>>value[i];
		}
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++){//外层循环,n为物品件数
			for(int j=v;j>=1;j--){//内层循环,v为背包质量 
				if(j>=weight[i])//放得下 
					dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
				else//放不下 
					dp[j]=dp[j];
			}
		}
		cout<<dp[v]<<endl;
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值