[編程題]【動態規划】背包問題
參考這個大神講解的背包問題后自己寫的代碼,up主講的太清楚了
題目信息
問題:現有背包。其中有四個商品。價值-體積如下
* 物品編號: 1 2 3 4
* 物品體積: 2 3 4 5
* 物品價值: 3 4 5 6
* 問:如何才能保證在背包容量為8的情況下裝的價值最大?
思路
背包問題,動態規划
思路
1、構建dp表,dp【i】【j】代表該i編號的背包為止容量為j的最大價值。先填表加深理解。
2、填完表如果要找出價值為k的容量的背包加入的物品標號只需要從i=dp.length-1,j=k的dp數組元素處回溯。
填完表如下(借視頻中up主的結果):
總結結論如下(借視頻中up主的總結):
理解了上述總結的思路,其實代碼就很容易寫出來了。
代碼如下
Java代碼
package interviewcode;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @author
* @create 2020/8/11 - 10:52
* @descp:
* 問題:現有背包。其中有四個商品。價值體積如下
* 物品編號: 1 2 3 4
* 物品體積: 2 3 4 5
* 物品價值: 3 4 5 6
* 問:如何才能保證在背包容量為8的情況下裝的價值最大?
*
* 步驟1:填表之后的結果:
* 0 0 0 0 0 0 0 0 0
* 0 0 3 3 3 3 3 3 3
* 0 0 3 4 4 7 7 7 7
* 0 0 3 4 5 7 8 9 9
* 0 0 3 4 5 7 8 9 10
* 步驟2:回溯
*/
//方法:動態規划
public class P28_背包問題 {
public static void main(String[] args) {
int[] size = new int[]{0,2,3,4,5}; //第0位放一個默認的0值,為了下邊方便取size[i]就為i號物品的體積
int[] money = {0,3, 4, 5, 6}; //第0位放一個默認的0值,為了下邊方便取money[i]就為i號物品的價值
int target = 14; //指定的背包大小
//調用
int[][] ints = dpWrite(size, money, target);
ArrayList<Integer> huisu = huisu(ints, size, target);
System.out.println("您輸入的背包大小是:"+target);
System.out.println("添加的物品編號是:"+huisu);
System.out.println("最大價值:"+ints[size.length-1][target]);
}
public static int[][] dpWrite(int[] size,int[] money,int targetValue){
//這里構造一個例如4*8的dp,行代表截止到i背包的最優組合的價值,j代表的背包的容量值
int[][] dp = new int[size.length][targetValue+1];
//初始化第0行的值
for(int j=0;j<=targetValue;j++){
dp[0][j] = 0;
}
//初始化第一列的值
for(int i=1;i<size.length;i++){
dp[i][0] = 0;
//dp[i][1] = 0;
}
//初始化中間值i
for(int i=1;i<size.length;i++){
for (int j=1;j<=targetValue;j++){
//如果第i號背包的體積小於當前的j背包容量,就保持和dp[i-1]值相同,即沒放入
if(size[i]>j){
dp[i][j] = dp[i-1][j];
}else{
/*即如果當前i號物品體積可以放入的話,就看預留該體積后剩余的價值在i-1號物品中的最大值加上該物品的價值和是否
是大於dp[i-1][j]的值,誰大取誰*/
dp[i][j] = Math.max(dp[i-1][j-size[i]>0?j-size[i]:0]+money[i],dp[i-1][j]);
}
}
}
//這樣就填表完成了。剩下的就是需要回溯取出看對應某價值target的物品組合是什么
//先打印一下填的表
/*for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[i].length; j++) {
System.out.print(dp[i][j]+"\t");
}
System.out.println();
}*/
return dp;
}
public static ArrayList<Integer> huisu(int[][] dp,int[] size, int t){
ArrayList<Integer> res = new ArrayList<>();
int i = dp.length-1;
int j = t;
while (i>0 || j>0){
if(dp[i][j]==dp[i-1][j]){
i--;
}else{
res.add(i);
j = j-size[i];
i--;
}
}
return res;
}
}
輸出:
測試1:例如:背包容量8,輸出物品編號和可以獲得的最大價值:
測試2:例如:背包容量14,輸出物品編號和可以獲得的最大價值: