01背包入门及解题思路

1.打表

动态规划的核心思想就是通过子问题的解,最终得出最终问题的解,当所有的子问题都解决了,最原始问题的解也就出来了,所以我们经常用一个数组dp来记录子问题的解,每当第一次求解时就把问题的解求出并存起来,当遇到相同问题时就不用重新求解,可以直接复用子问题的解。

这里告诉我们2个关键点,一是可以通过求解子问题的解来得出原问题的解二是整个dp数组打表完成,答案就在dp数组里面,因为每个子问题都满足最优子结构即每个子问题的解都是最优解

2.最优子结构

动态规划告诉我们,要使用动态规划,必须满足重复子问题和最优子结构,最优子结构就是每个子问题的求解都是最优解。从这里我们可以看出,每个子问题的最优解可能有n种策略得出,但不管有几种策略,得到子问题的解就是所有策略最优的结果

3.无后效性

无后效性就是当子问题的解确定下来了,就一直不会改变,一直是这个结果,不会受到后面的计算而改变该子问题的解。比如dp[5]=5,那么这个子问题的解确定下来之后就不会再改变。

动态规划三步走

1.定义dp数组的含义:要求谁就定义谁

2.根据观察列出状态转移方程

3.找出初始条件

此题目出自算法笔记

1.我们根据第一步,定义dp数组的含义,由于题目要求使得背包内物品的总价值最大,所以我们定义取前i件物品装入容量为v的总价值最大。

2.观察

刚开始,物品为0件,也就没有存放物品之说,所以第一行全部填0,背包容量为0,所以也没有容量,第一列全部填0。

        当物品数量为1时,容量为0时,背包放不下,因为第一件物品重量为3,所以背包价值为0,同理,当背包容量为1,2时也是0,背包同样存不下。

        当背包容量为3时,根据观察,这里可以选择存下第一个物品,所以此时最优子结构是当背包容量为3时,背包价值为4对吧,那么这个4是怎么的出来的呢?我们暂且不表,因为还比较难看出来,我们只知道当物品重量小于等于背包容量时,可以存下第一个物品,即w[i]<=j时,dp[i][j]=4,因为只有一个物品,所以当背包容量大于3时,都只能存下一个物品,所以背包容量为4-10时,背包最大总价值都为4。

         当物品数量为2时,背包容量0-2都满足不了存放任何一个物品,所以背包总价值为0,当背包容量为3时,能存下第一个物品,但是存不下第二个物品对吧?所以此时最大的背包价值就是上一个物品的最大背包价值,即当w[i]>j(第二个物品重量大于背包容量时),最优的选择就是选择上一个物品,此时最大价值为4。此时可以列出第一个dp转移方程,dp[i][j]=dp[i-1][j]。同理当背包容量为4时,只能选择上一个物品,最大价值为4。

         当背包容量为5时,我们可以选择2个物品,第一个物品重量为3能被选择,第二个物品重量为5也能选择,那么选择哪个价值更大呢?即可以说第二个物品选还是不选的问题,因为选和不选都有可能使背包价值更大,为比较2种选择的最大值。当不选择时,就是选择上一个物品dp[i-1][j],最大价值为4,当选择时,最大价值就是5,经过肉眼观察比较我们得出选择第二个物品为最优解。选择时我们要减去背包容量,同时加上第二个物品的价值。此时我们可以列出状态转移方程,即w[i]<=j(第二个物品的重量小于背包容量),dp[i][j]=max(dp[i-1][j](不选择),dp[i-1][j-w[i]]+v[i](选择)),可以带入试试,当背包容量为5时,选择第二个物品时dp[1][0]+5表示,第一个物品不选,选择第二个物品。因为dp[1][0]为0嘛,表示在只有一个物品且容量为0时,背包最大值为0。在只有一个物品遇见过的时候已经记录过答案了,直接复用。同理,当背包容量为6-7时,都是选择第二个,背包价值最大为5,

        当背包容量为8时,此时2个物品都能放下,即w[i]<=j(第二个物品小于背包容量),dp[i][j]=dp[i-1][j-w[i]]+v[i],合并到dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i],由于都是要选择第二个,dp[i-1][j-w[i]]+v[i]的值始终要大于dp[i-1][j],所以可以合并。带入看看,当背包容量为8,选择第二个物品时dp[1][4]+5,而dp[1][4]我们在物品只有一个时已经记录过了,dp[1][4]=4,所以背包最大值为4+5=9。

至此,所有的条件已经找齐了 

列出状态转移方程

当w[i]>j时,dp[i][j]=dp[i-1][j];

当w[i]<=j时,dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);

3.找出初始条件,即当有0件物品可以选时,第一行全为0,当背包容量为0时,第一列全为0。因为创建数组时默认全部赋值为0,所以初始条件可以忽略掉

输入

5 8
3 5 1 2 2
4 5 2 1 3

完整代码

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;


int n,v;			//有几件物品,背包容量 
int w[100];			//重量 
int c[100];			//价值 
int dp[100][100]; 	//dp数组 
int main(){


	//输入 
	cin>>n>>v;
	for(int i=1; i<=n; i++){		//输入重量 
		cin>>w[i];
	}
	for(int i=1; i<=n; i++){		//输入价值 
		cin>>c[i];
		
	}
	
	
	/*因为创建数组时默认全部赋值为0,所以初始条件可以忽略掉。*/
	//dp 
	for(int i=1; i<=n; i++){		//从第1件物品开始选 
		for(int j=1; j<=v; j++){	//背包容量 
			if(j<w[i]){
				dp[i][j]=dp[i-1][j];
			}else{
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+c[i]);
			}
		}
	} 
	
	cout<<dp[n][v];					//输出最大值 
	return 0;
} 

 输出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值