01背包问题

               01背包问题描述:给定N个体积为V1....Vn,价值为P1...Pn的物品和一个体积为V的包,求能够装进包中物品的最大价值。

为了设计一个动态规划算法,我们需要导出状态转移方程。先考虑原问题的子问题,假设我们考虑前i个问题,背包容积为j,记将前i个物品装到容积为j的包中最大总价值为W[i,j];每个物品只有选择和不选择两种情况,我们根据第i个物品是否选择进行分类。在不包含第i个物品的最优解价值为W[i-1,j],在包含第i个物品的最优解中,最优子集是该物品和前i-1个物品中能够放入最大体积 j - v[i](j-v[i]>0)的背包的最优解组成。这时候最优解为p[i]+W[i-1,j-v[i]];于是在前i个物品的最优解是这两种情况的最大值。特殊情况,第i个物品本身体积大于包时,从前i个物品中选出的最优解价值等于从前i-1个物品中选出的最优解的价值。

     状态转移方程:W[i,j]=max{ W[i-1][ j ] , W[ i-1][ j-v[i]]+p[ i] }(j-v[i]>=0),若j-v[i]<0,则W[i,j]=W[i-1,j].

上面状态转移方程时间和空间复杂度均为O(VN),时间复杂度无法优化,而空间复杂度还可以继续优化。我们可以使用一维数组来代替上面的二维数组,则状态转移方程如下:

      W[ j ]=max{W[ j ],W[j-v[ i ]]+p[ i ]} (j>=v[ i ])

 其中左边的W[j]是W[i,j],右边的W[j]是W[i-1,j],W[j-v[i]]是W[i-1][j-v[i]].可以用下面循环:

for(i=1;i<=N;i++)

    for(j=V;j>=v[i];j--)

           ......

     这样一来空间复杂度为O(V);我们再来看初始化的问题,背包问题有两种情况。第一种要求背包装满,在初始化时W[0]=0,而W[1..V]= -1,因为在0个物品情况下,只有体积为0的背包可以看做什么也不放入即是他的合法解,而包体积j>0时是无论如何也装不满的,于是找不到合法的解,标志为-1;第二种是不要求背包装满的情况,则可以将W[0...V]=0全部初始化为0,这时有0个物品,包里什么也不装就是它的合法解,总价值都为0;下面两种情况C++代码:

</pre><pre name="code" class="cpp">#include<iostream>
using namespace std;
#define MAX_SIZE 500
int N, V;
int W[MAX_SIZE];
int p[MAX_SIZE];
int v[MAX_SIZE];
int main(){
	int i,j,pos;
	memset(W, -1, sizeof(W)); //边界初始化
	W[0] = 0;
	cin >> N >>V;
	for (i = 1; i <= N; i++)
		cin >> v[i] >> p[i];    
	for (i = 1; i <= N; i++){
		for (j = V; j >= v[i]; j--){
			pos = j - v[i];
			if (W[pos] != -1 && W[pos]+p[i] > W[j])
				W[j] = W[pos] + p[i];
		}
	}
	cout << W[V] << endl;
	return 0;
}</span>
#include<iostream>
using namespace std;
#define MAX_SIZE 500
int N, V;
int W[MAX_SIZE];
int p[MAX_SIZE];
int v[MAX_SIZE];
int Bag01(int v[], int p[]);
int main(){
	int i,j,pos;
	memset(W,0, sizeof(W)); //边界初始化
	cin >> N >>V;
	for (i = 1; i <= N; i++)
		cin >> v[i] >> p[i];    
	for (i = 1; i <= N; i++){
		for (j = V; j >= v[i]; j--){
			pos = j - v[i];
			if ( W[j]<W[pos]+p[i])
				W[j] = W[pos] + p[i];
		}
	}
	cout << W[V] << endl;
	return 0;
}</span>


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值