NOJ-1577-0-1背包问题

280 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

0-1背包问题

描述:

一个背包容量为c ,现有n件物品,求能装入背包的最大重量是多少?

输入:

先输入两个正整数n、c(0<n、c<1000),表示物品的件数和背包容量,再输入n个正整数,分别是这n件物品的重量。

输出:

输出能装入背包的最大重量。

输入样例:

5 5023 18 13 35 24

输出样例:

48

思路

方法一:

0-1背包的裸题,那就可以直接写一个01背包的动态转移方程:dp[j]=max(dp[j],dp[j-w[i]]+p[i])。dp[j]的意思是:当背包已装j的重量的物品时的最大价值。那么它可以由背包已装j-w[i]时最大的价值进行转移,即由dp[j-w[i]]+p[i]得到。注意每一次要将dp[]设置为0,因为背包此时无价值。当状态方程枚举结束后,我们再从 dp[]数组中找一遍,求得答案maxx=max{dp[i]}(i from 0 to c),输出答案maxx。这种动态规划的方法的时间复杂度为O(n^2).

ps:0-1背包也可以写成二维dp[][],只是这样写成滚动数组可以更加节省空间。

方法二:

除了直接写0-1背包的动态转移方程,还可以直接写dfs,每一个背包无非就是取和不取两个状态,如果要取则要求背包容量 res>=w[now]。分别用ans1,ans2表示取当前物品,不取当前物品的最大价值,dfs返回max(ans1,ans2),dfs的终止条件是now ==n+1。时间复杂度(2^n)。

ps:方法二相较于方法一思维上更加简单,容易想到,但是代码就相对麻烦,并且时间复杂度不够优秀,当然如果加上记忆化搜索后时间复杂度和动态规划是相当的。我个人更喜欢方法一。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=	2000+50;
int n,c,w[maxn],dp[maxn],p[maxn];
int main(){
	int i,j;
	scanf("%d%d",&n,&c);
	for(i=1;i<=n;i++)cin>>w[i],p[i]=w[i];
	for(i=1;i<=n;i++){
		for(j=c;j>=1;j--){
			if(j-w[i]>=0&&dp[j]<dp[j-w[i]]+p[i]){
				dp[j]=dp[j-w[i]]+p[i];
			}
		}
	}
	int maxx=0;
	for(i=0;i<=c;i++)
		if(maxx<dp[i])
			maxx=dp[i];
	cout<<maxx<<endl;
	return 0;
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=	2000+50;
int n,c,w[maxn],p[maxn];
int dfs(int now,int res){
	if(now==n+1)return 0;
	int ans1=0,ans2=0;
	if(res>=w[now]){
		ans1=dfs(now+1,res-w[now])+p[now];
	}
	ans2=dfs(now+1,res);
	if(ans1>=ans2)return ans1;
	return ans2;
}
int main(){
	int i,j;
	scanf("%d%d",&n,&c);
	for(i=1;i<=n;i++)cin>>w[i],p[i]=w[i];
	cout<<dfs(1,c)<<endl;
	return 0;
}