01背包 和 完全背包

题目:有价值为v[i]、重量为w[i]的N个物品(每个物品仅有一个)及容量为W的背包,现要求在物品总重量不超过W的前提下选择总价值尽可能高的物品放进背包里。

分析用一个二维数组T[i][j]表示背包的容量为j,物品数为1~i时的最大价值,T[i][j]只有选择第i种物品或者不选第i种物品两种可能,因此状态方程可写成T[i][j]=max(T[i-1][j],T[i-1][j-w[i]]+v[i]),其中前一种是不选第i种物品,后一种是选择第i种物品。

这种方法时间和空间复杂度都是O(N*W), 空间复杂度可以优化到O(W), 即使用一维数组, 代码如下:

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

    {  
        for(int j = W; j >= w[i]; j--)  
        {  
			T[j]=max(T[j],T[j-w[i]]+v[i]);
		}
 	}

一般求最优解有两种问法: 恰好装满背包和重量不超过背包,而它们的初始化是不同的。

1.恰好装满背包,除了T[0]=0外T[1....W]均为-∞, 如果不能恰好装满背包,则T[W] =-∞ , 则说明没有最优解。

2.重量不超过背包,T[0....W]均初始化为0。

附上题目代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int Max=1000+5;
int w[Max],v[Max],T[Max];
int main()
{
    int N,W;
    cin>>N>>W;
for(int i=1;i<=N;i++)
{
    cin>>v[i]>>w[i];
for(int i=0;i<=W;i++)T[i]=0;
for(int i=1;i<=N;i++)
for(int j=W;j>=w[i];j--)
{
    T[j]=max(T[j],T[j-w[i]]+v[i]);
}
    cout<<T[W]<<endl;
    return 0;
}                            

把题目改为恰好装满背包,代码如下(注意与上述代码不同之处)

#include<iostream>
#include<algorithm>
using namespace std;
const int Max=1000+5;
const int INFTY=-1000000; 
int w[Max],v[Max],T[Max];
int main()
{
int N,W;
cin>>N>>W;
for(int i=1;i<=N;i++)
{
	cin>>v[i]>>w[i];
}
for(int i=1;i<=W;i++)T[i]=INFTY;
T[0]=0;
for(int i=1;i<=N;i++)
	for(int j=W;j>=w[i];j--)
	{
		T[j]=max(T[j],T[j-w[i]]+v[i]);
	}
	if(T[W]<0)
	cout<<"It's impossible!"<<endl;
	else
	cout<<T[W]<<endl;
return 0;
 } 

题目再次修改,如果每件物品都有无穷多件,则为完全背包问题。每种物品有多种选择,选0件、1件……n件(不超过背包能装的重量),  用二维数组表示T[i][j]=max(T[i-1][j-k*w[i]] + k*v[i]), 0<= k*w[i]<= W。实际上,确是直接使用一维数组,即如果当前背包未满,继续往里装第i种物品。

for(int i=1;i<=N;i++)
	for(int j=w[i];j<=W;j++)
	{
	    T[j]=max(T[j],T[j-w[i]]+v[i];
	}

发现完全背包问题跟01背包的区别在于内层循环的顺序不同。

例题1:01背包 HDU2602

例题2:完全背包 HDU1114



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值