0-1背包问题

1. 0-1背包问题

0-1背包问题模型:

一个总容量V的背包和N件物品,每件物品都有其体积w,价值v;每个物品是否在背包中即0-1情况,故称该种问题为0-1背包问题。要求背包能装下价值尽可能多的物品,求最大价值;

状态描述:dp[i][j]表示第i件物品对于当前占用容量为j的价值状态,其中1<=i<=n,0<=j<=V;

状态分析:第i件物品是否加入背包,

                (1)加入,dp[i][j]等于dp[i-1][j-w]+v,第i-1件相对于j-wi的占容最大价值的最大价值加第i件价值;

                  (2)   没加入,d[i][j]等于dp[i-1][j],即与第i-1件到j占容的最大价值;

 状态转换:

 \\dp[0][j]&=0; \\dp[i][j]&=max\lbrace dp[i-1][j-w]+v,dp[i-1][j]\rbrace (j-w> 0)

转换结果:dp[N][V],第N件物品到占容为V的最大价值状态

测试数据:

70 3

71 100
69 1
1 2

状态分析表如下所示:

i \ j12...686970
100...000
200...00+10+1
320+2...20+21+2

 

 Code:

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,N;//V为容量,N为个数
vector<int> dpcol(1000,0);
vector<vector<int>> dp(100,dpcol);//N<=100,V<=1000
struct goods{
	int w;//权重或表示为占容
	int v;//价值value
};
vector<goods> goods(100,{0,0});
int main(){
	int w,v;
	while(cin>>V>>N){
		for(int i=1;i<=N;i++){
			cin>>w>>v;
			goods[i]={w,v};
		}//输入物品
		for(int j=1;j<=V;j++){//0件物品的所有价值为0
			dp[0][j]=0;
		}//初始化第0件状态
		for(int i=1;i<=N;i++){//物品V
			for(int j=V;j>=goods[i].w;j--){//倒序,由上一轮数据更新,能放入i物品
				dp[i][j]=max(dp[i-1][j-goods[i].w]+goods[i].v,dp[i-1][j]);
			}
			for(int j=goods[i].w-1;j>=0;j--){//不能放入i物品,照抄上一轮到j的价值,且//保证了dp[i][0]=0;
				dp[i][j]=dp[i-1][j];
			}
		}
		cout<<dp[N][V]<<endl;
	}
	return 0;
}
/**
70 3
71 100
69 1
1 2

3
 */

优化Code:

1.dp只受上一轮结果影响,故将二维dp[i][j]一维话dp[j]。

2.for(V....goods[i].w) dp[j],未加入i物品时暂存上一轮dp,省略了二维的抄作业行为。

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
int V,N;
int w,v;
vector<int> dp(101,0);
struct goods{
	int w,v;
};
vector<goods> goods(101,{0,0});
int main(){
	while(cin>>V>>N){
		for(int i=1;i<=N;i++){
			cin>>w>>v;
			goods[i]={w,v};
		}
		for(int j=0;j<V;j++){
			dp[j]=0;
		}
		for(int i=1;i<=N;i++){
			for(int j=V;j>=goods[i].w;j--){
				dp[j]=max(dp[j],dp[j-goods[i].w]+goods[i].v);
			}
		}
		cout<<dp[V]<<endl;
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值