[編程題]【動態規划】背包問題


[編程題]【動態規划】背包問題

參考這個大神講解的背包問題后自己寫的代碼,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主的結果):

image-20200811132339620

總結結論如下(借視頻中up主的總結):

image-20200811132425407

理解了上述總結的思路,其實代碼就很容易寫出來了。

代碼如下

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,輸出物品編號和可以獲得的最大價值:

image-20200811132013853

測試2:例如:背包容量14,輸出物品編號和可以獲得的最大價值:

image-20200811132242486


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM