假设有abcde5个物品,重量为w1...,价值为v1...,背包的承重量为c,怎么放的价值更高数组
1、0/1背包问题优化
5中物品只有一件,动态规划的子问题是前i个物品放在承重量为j的背包中,状态变量:dp[i][j]spa
遍历时i在外层,j在内层,也就是每次循环先求出前i-1个物品在不一样载重量的状况下的自大价值code
而后增长一个物品,也就是前i个物品。blog
而在求前i个物品的最大价值时根据前i-1的结果:class
1.当前载重量<新增的第i件物品的重量w[i],也就是装不下变量
dp[i][j] = dp[i-1][j]循环
2.装得下遍历
dp[i][j] = max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]):比较装和不装,其中若是装当前物品,那么重量占了w[i],前边i-1件物品只能使用j-w[i]的重量di
到这里时间复杂度无法优化,可是还能优化空间复杂度
咱们能够观察到,这里的i只是记录进行到前多少件物品了,其实咱们不须要前几件的结果,咱们须要的是最后的结果,因此咱们没有必要记录
i的信息。能够用一个一维数组dp[j]只记录当前信息i件物品下,不一样载重量的价值。而后每次都更新。更新到最后就是想要的
这里虽然不记录i的信息,可是仍是要保留循环,表明这是前i件的状况,i不一样的状况下,dp[j]是不一样的。
注意这里须要倒着遍历,由于dp[j]会不断更新,前边更新的结果不能影响后边
若是从前边开始,前边的dp[j]就会更新为i的状态,i-1的状态就消失了,可是后边须要这些
若是从后边开始,前边的用不到后边的结果
public void p01(int[] w,int[] v,int c){ int[] dp = new int[c+1]; for (int i = 0; i < w.length; i++) { // 注意这里须要倒着遍历,由于dp[j]会不断更新,前边更新的结果不能影响后边 // 若是从前边开始,前边的dp[j]就会更新为i的状态,i-1的状态就消失了,可是后边须要这些 // 若是从后边开始,前边的用不到后边的结果 for (int j = c; j >=w[i]; j--) { dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]); } } System.out.println(dp[c]); }
2.彻底背包问题
物品数量没有限制
public void pComplete(int[] w,int[] v,int c){ int[] dp = new int[c+1]; for (int i = 0; i < w.length; i++) { //这里应该从前日后遍历,01背包不能从前日后的缘由实际上是若是当前承重量能够装下多件第i件物品时 //01问题不能装多个,因此装完后要用前一次的状态比较(前一次确定是没有装i的) //可是彻底背包不一样,装完后要用最新的状态比较,由于还能够继续装i for (int j = w[j]; j <=c; j++) { dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]); } } System.out.println(dp[c]); }