1. 01背包
01背包就是指背包里面每种物品只能用一次,在有限的空间内求装入物品的最大价值的问题。
1. 题面:
有一容量为m的背包。现在要从n件物品中选取若干装入背包中,每件物品i的重量为w[i],价值为p[i],定义一种可行的背包装载为:背包中物品的总重量不能超过背包的容量,并且一个物品要么全部选取,要么不选取。定义最佳装载是指所装入的物品价值最高,并且是可行的背包装载。
输入输出:
样例输入 样例输出
11 (背包容量) 23(总价值)
4(物品数量)
2 4 6 7(物品重量)
6 10 12 13(物品价值)
2. 递归解法
考虑到这个题目,用贪心算法显然是鼠目寸光的。所以思考其他思路。自顶向下地看这个题目,对于第n件物品而言,无非有两个状态(选择):取或者不取。如果取,在获得这件物品价值地同时,也要承担其重量,如果不取,就无需承担,当然也得不到它的价值。满足无后效性。那么,这种问题就可以递归地求解了。
//返回第n件物品的最大价值,weight为背包剩余容量
int dfs(int n,int weight) {
if(n==0||weight==0) return 0;//递归终止条件
int a = dfs(n-1,weight]);//不取,直接返回n-1的状态,不消耗weight
int b = dfs(n-1,weight-w[n])+v[n];//取,消耗掉w[n]空间的同时获得了v[n]的价值
return a>b?a:b;//返回最大值
}
3. 优化递归:记忆化搜索
对于上述递归解法,每求一次dfs(n)就要用到很多次dfs(2),dfs(3)等,而这些必须用一次算一次,增加了时间复杂度。所以,我们考虑使用一个数组把他们存起来,即记忆化搜索,又叫备忘录方法,这样就可以减小时间复杂度。
int dp[100005];
int dfs(int n,int weight) {
if(n==0||weight==0) return 0;//递归终止条件
if(dp[n]!=-1) return dp[n];
int a = dfs(n-1,weight]);//不取,直接返回n-1的状态,不消耗weight
int b = dfs(n-1,weight-w[n])+v[n];//取,消耗掉w[n]空间的同时获得了v[n]的价值
if(a>b) {
dp[n] = a;
}else dp[n] = b;
return dp[n];//返回最大值
}
4.动态规划
对于这类无后效性,备忘录的问题,使用动态规划显然是最佳解法。对于这个题,我们使用f[i][j]作为取第i件物品时容量为j的最大利润,即可推导出状态转移方程:
f[i][j] = max(f[i-1][j],f[i-1][j-w[i]]+v[i])
由此即可写出基本代码:
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (w[i] > j) {
f[i][j] = f[i - 1][j];
}
else {
f[i][j] = f[i - 1][j] > f[i - 1][j - w[i]] + v[i] ? f[i - 1][j] : f[i - 1][j - w[i]] + v[i];
}
}
}
5.滚动数组
在这个过程中,我们发现所要的仅仅是f[n][m],即n个物品容量为最大容量m时的情况,而前面n-1的数组迭代都是无意义的。因此,可以用一维数组代替二维数组,进一步优化空间复杂度。此时的状态转移方程如下:
f[j] = max(f[j],f[j-w[i]]+v[i])
此时得到的代码:
for (int i = 1; i <= n; i++) {
for (int j = m; j >=w[i]; j--) {
f[j] = max(f[j],f[j-w[i]]+v[i]);
}
}
这里代码中的第二行使用了由后向前的遍历方式,而完全背包问题则恰好相反,是由前到后的遍历方式。举个例子,若 j=4:
f[4] = max(f[4],f[4-w[i]]+v[i]);
因为是由后到前,我们再看遍历到j=2时的情况:
f[2] = max(f[2],f[2-w[i])+v[i]);
若w[i]=2,初始化之后,因为f被置为0,先算w[4]时w[2]是为0的,这样就避免了f[2]被多次相加的问题。反之,若是完全背包问题,先计算f[2],f[2]的值已经不为0,此时计算f[4] = max(f[4],f[2]+v[i]);这样j每翻一倍,f[4]就也会翻一倍,符合完全背包问题的要求。
最简单的例子如洛谷采药,疯狂的采药,又如蓝桥杯2018年的分包子问题,2021年的天平问题等。
标签:多重,背包,weight,int,dfs,01,物品,dp From: https://www.cnblogs.com/jianghanqed/p/16107536.html