经典动态规划问题
给你⼀个可装载重量为W 的背包和 N 个物品,每个物品有重量和价值两 个属性。其中第i 个物品的重量为wt[i],价值为 val[i] ,现在让你⽤ 这个背包装物品,最多能装的价值是多少?
1.明确背包问题的实质:
1)第一个想法是使用贪婪法,每次取价值最高的那个,但是这种办法并不一定能够得到最优,例如10kg的背包 有8kg价值9元的物品1,3kg 价值3元的物品2,和8kg价值7元的物品3;
如果选择物品1 背包无法装其他的物品 价值为9;
但是 选择物品2和物品3 价值为10;
2)因为对于物品来说是个整体,要么不装 要么装,当背包无法装入物品时,无法获得这个物品的价值,所以要获得更大的价值,最简单的办法就是枚举所有的可能。
3)动态规划的本质就是枚举,只是通过已经计算出来的结果减少计算量,相当于通过建立一个备忘录,利用空间换时间。
动态规划的套路
1.建立动态规划数组,并明确其含义;
dp[i][j]
i:代表选择第i个物品
j:代表当前背包的重量
dp[i][j]:代表当前背包中物品的价值
2.赋予初值
i=0 即无物品选择时 dp[0][j]=0;
3.状态和选择
背包的状态即 i, j
对于i来说 第i个物品选择放入背包和不放背包 两种状态
根据i的状态 j = (j - w) + w(装入此物品,要腾出 w 的空间,腾出之前的价值根据已经计算的价值获得,若j-w<0,则无法装入,选择不放。
则
1)不放: dp[i][j]=dp[i-1][j];
2) 放 :dp[i][j]=dp[i-1][j-w]+v;
(dp[i-1][j-w] 代表不放这个物品 只有j-w空间时的最大价值,v 代表当前物品价值)
代码:
import java.util.*
Class Solution{
public packetProblem(int[] w, int[] v, int total){
int m = w.length; //物品数量
int[][] dp = new int[m + 1][total + 1]; //建立dp table
//dp[0][j]==0 物品 i 从 1 开始
for(int i = 1; i <= m; i++){
for(int j = 0; j <= total; j++){
//作选择
//1.如果空间不足 不选该i物品
if(j - w[i - 1] < 0)
dp[i][j] = dp[i - 1][j];
//2.空间足够
else {
//比较选择和不选择i物品价值 决定dp[i][j]
dp[i][j] = Math.max(dp[i - 1][j - w[i - 1]] + v[i - 1], dp[i - 1][j]);
}
}
}
//答案是选择到m件商品 容量为total时
return dp[m][total];
}
}
推荐一个背包问题dp table 的网站
https://misakasister.github.io/Online_0-1_Knapsack/index.html
一目了然