完全背包问题

问题:

有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值
1≤n≤100

1≤wi,vi≤100

1≤W≤10000

思考:

其实这个问题01背包问题的区别在与,这里的每个物品都是可以重复取的。而01背包问题就只能取一次;

在原01背包问题中:

递推式为: dp [ i ] [ j ] = max( dp[ i-1 ] [ j - weight [ i ] ] + value [ i ] , dp[ i-1 ] [ j ] )

式子的含义为 : 当我背包的容量为 J 时,我是否取第 i 个物品

(1)如果取: **dp[  i-1 ] [ j - weight [ i ] ] + value [ i ]** : 
			背包要放入物品 **i** , 那么背包必须有容纳得下 **i** 物品的空间 ,
			所以前一状态背包用量有 :**[ j - weight [ i ]  ]** , 
			既然我的物品只能取一次,所以  **[ i - 1 ]** (过度回取第 i- 1 号物品 的情况,保证i 号物品 只被取一次), 才有此式子。
 (2) 如果不取,那么就是直接返回前状态 : dp[ i-1 ] [ j ] 

那么ok, 我们现在想一想,如果我可以反复取 i 号物品(在容量J 允许的情况下) ,
那么如果我取了 i 号物品 一次后, 我就不需要过度回 取 i- 1 号物品的 状态了 。
因为假设取了一次之后,背包容量还可以再一次纳入此物品,那么 只需要在我取了第一次的基础上,在加一次就ok 啦。而第一次取得记录已经被记录入 dp [ i ] [ j - weight [ i ] ] + value[ i ] (为什么不是 i-1 ??? -----已经说了:可以多次取,不需要过度回 i-1 的状态来保证只取一次)了。

所以 最 终 结 论 完全背包问题 的 递 推 式 :
dp[ i ] [ j - weight [ i ] ] + value [ i ] , dp[ i-1 ] [ j ]

举例:

物品价值重量
物品143
物品254
物品332

容量vol = 7;
(直接跳到允许放入的时候)
1) dp [ 1 ] [ 3 ] = max( dp[ i ] [ 3-3 ] + value [ 1 ] , dp [ 0 ] [ 3 ] )
==> dp [1] [3] = max ( 0 + 4 , 0)

2)dp [ 1 ] [ 4 ] = max( dp[ 1 ] [ 4-3 ] + value [ 1 ] , dp [ 0 ] [ 4 ] )
==> dp [1]\ [4] = max ( 0 + 4 , 0)

3)dp [ 1 ] [ 5 ] = max( dp[ 1 ] [ 5-3 ] + value [ 1 ] , dp [ 0 ] [ 5 ] )
==> dp [1] [5] = max ( 0 + 4 , 0)

!!!重点来了
4)dp [ 1 ] [ 6 ] = max( dp[ 1 ] [ 6-3 ] + value [ 1 ] , dp [ 0 ] [ 6 ] )
dp [ 1 ] [ 6 ] = max( dp[ 1 ] [ 3 ] + value [ 1 ] , dp [ 0 ] [ 6 ] )
==> dp [1] [6] = max ( 4 + 4 , 0)
!!是不是在原来已经放了物品1的基础上又放了物品!!

如果是01背包问题就是:
dp [ 1 ] [ 6 ] = max( dp[ 1-1 ] [ 6-3  ]  + value [ 1 ]   , dp [ 0 ] [ 6 ] ) 
dp [ 1 ] [ 6 ] = max( dp[ 0 ] [ 3 ]  + value [ 1 ]   , dp [ 0 ] [ 6 ] ) 
==>  dp [1] [6]  = max(0 + 4  ,  0)

代码

#include <string.h>
using namespace std;

int main()
{
	int n;	
	int vol ;
	
	cin>>n;
	int value[n]={0};
	int weight[n]={0};
	int dp[10][10] ={0};
	
	for(int i=1;i<=n;i++)
	{
		cin>>value[i];	
	}
	
	for(int j=1;j<=n;j++)
	{
		cin>>weight[j];
	}
	
	cin>>vol;
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=vol;j++)
		{
			if(weight[i]<=j)
			{
				dp[i][j] = max(dp[i][j - weight[i]] + value[i], dp[i-1][j]);
			}
			else
			{
				dp[i][j] = dp[i-1][j];
			}
			
		}
	 }
	 for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=vol;j++)
		{
			cout<<dp[i][j]<<" "; 
		}
		cout<<"\n";
	}
	cout<<dp[n][vol]

友情提示:

关于01背包问题,推荐一位博主:
[简书] 01背包问题

~第一次写博,可能很罗嗦,也可能有错误,欢迎指点,谢谢亲故

~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值