[编程题]【动态规划】背包问题

[编程题]【动态规划】背包问题

参考这个大神讲解的背包问题后自己写的代码,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

posted @ 2020-08-11 13:26  北鼻coder  阅读(1696)  评论(1编辑  收藏  举报