首页 > 其他分享 >动态规划之背包问题

动态规划之背包问题

时间:2023-04-30 15:01:02浏览次数:27  
标签:index 背包 capacity weight int value length 动态 规划

题目

现有一背包的容量为capacity

现有一些物品,物品有重量和价值两个属性,物品的重量存在weight数组中,物品的价值存在value数组中,为了方便,其中没有负数。

限制的条件是每个物品只有一种,要么放入背包,要么不放入,如何才能使得背包获得最大的价值,也就是在不超过背包容量的情况下背包能从物品中获得最大的价值,最终的结果,背包可以不被放满。

思路一:普通递归

两种选择,对于当前index下标的数组值,可以选择要和不要两种情况,比较两种情况下取获得价值大的。

public static int maxValueOne(int capacity, int[] weight, int[] value){
    if(capacity < 0 || weight == null || value == null || weight.length == 0 || value.length == 0 || weight.length != value.length){
        return 0;
    }
    return processOne(capacity, weight, value, 0);
}

/**
 * @param rest  背包剩余重量
 * @param weight 重量数组
 * @param value 价值数组
 * @param index 数组下标
 * @return
 */
public static int processOne(int rest, int[] weight, int[] value, int index){
    //当剩余重量小于0时,表示当前物品不能要,注意:有可能重量等于0还有价值的情况
    //如果rest 为负数表示当前的index是不可用的,所以value[index]值就无效,返回 -1
    if(rest < 0){
        return -1;
    }

    if(index == weight.length){ //超过界限不取
        return 0;
    }

    int next = processOne(rest - weight[index], weight, value, index +1);
    int ans1 = 0;
    if(next != -1){
        //要当前物品
        ans1 = value[index] + next;
    }
    //不要当前物品
    int ans2 = processOne(rest, weight, value, index + 1);
    //取最大值
    return Math.max(ans1, ans2);
}

思路二:傻缓存方式

分析有没有重复的过程,可以根据下标配合剩余背包容量进行确认值,假设背包容量为20,且当前index = 3,状态一是取0和2,不取1,此时剩余背包容量rest = 20 - 4 = 16,状态二是取1,不取2和3,此时剩余容量也是16,有重复过程。

动态规划之背包问题_Math

  public static int maxValueTwo(int capacity, int[] weight, int[] value){
        if(capacity < 0 || weight == null || value == null || weight.length == 0 || value.length == 0 || weight.length != value.length){
            return 0;
        }
        int N = weight.length;
        int[][] dp = new int[N+1][capacity+1];
        //初始化
        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= capacity; j++) {
                dp[i][j] = -1;
            }
        }

        return processTwo(capacity, weight, value, 0, dp);
    }

    public static int processTwo(int rest, int[] weight, int[] value, int index, int[][] dp){
        if(rest < 0){
            return -1;
        }

        if(index == weight.length){
            return 0;
        }

        if(dp[index][rest] != -1) {
            return dp[index][rest];
        }

        int next = processTwo(rest - weight[index], weight, value, index+1, dp);
        int ans1 = 0;
        if(next != -1){
            ans1 = value[index] + next;
        }
        int ans2 = processTwo(rest, weight, value, index+1, dp);
        int max = Math.max(ans1, ans2);
        dp[index][rest] = max;
        return max;
    }

思路三:动态规划精髓-直接取值法

public static int maxValueThree(int capacity, int[] weight, int[] value){
    if(capacity < 0 || weight == null || value == null || weight.length == 0 || value.length == 0 || weight.length != value.length){
        return 0;
    }
    int N = weight.length;
    int[][] dp = new int[N+1][capacity+1];
    //直接赋值
    for (int i = N-1; i >= 0; i--) {
        for (int j = 0; j <= capacity; j++) {

            //i位置的值取
            int next = j - weight[i] < 0 ? -1 : dp[i+1][j-weight[i]];
            int ans1 = 0;
            if(next != -1){
                ans1 = value[i] + next;
            }
            //i位置的值不取
            int ans2 = dp[i+1][j];
            //比较然后存值
            dp[i][j] = Math.max(ans1, ans2);
        }
    }

    return dp[0][capacity];
}

总结测试

public class Knapsacks {

    public static int maxValueOne(int capacity, int[] weight, int[] value){
        if(capacity < 0 || weight == null || value == null || weight.length == 0 || value.length == 0 || weight.length != value.length){
            return 0;
        }
        return processOne(capacity, weight, value, 0);
    }

    /**
     * @param rest  背包剩余重量
     * @param weight 重量数组
     * @param value 价值数组
     * @param index 数组下标
     * @return
     */
    public static int processOne(int rest, int[] weight, int[] value, int index){
        //当剩余重量小于0时,表示当前物品不能要,注意:有可能重量等于0还有价值的情况
        //如果rest 为负数表示当前的index是不可用的,所以value[index]值就无效,返回 -1
        if(rest < 0){
            return -1;
        }

        if(index == weight.length){ //超过界限不取
            return 0;
        }

        int next = processOne(rest - weight[index], weight, value, index +1);
        int ans1 = 0;
        if(next != -1){
            //要当前物品
            ans1 = value[index] + next;
        }
        //不要当前物品
        int ans2 = processOne(rest, weight, value, index + 1);
        //取最大值
        return Math.max(ans1, ans2);

    }

    public static int maxValueTwo(int capacity, int[] weight, int[] value){
        if(capacity < 0 || weight == null || value == null || weight.length == 0 || value.length == 0 || weight.length != value.length){
            return 0;
        }
        int N = weight.length;
        int[][] dp = new int[N+1][capacity+1];
        //初始化
        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= capacity; j++) {
                dp[i][j] = -1;
            }
        }

        return processTwo(capacity, weight, value, 0, dp);
    }

    public static int processTwo(int rest, int[] weight, int[] value, int index, int[][] dp){
        if(rest < 0){
            return -1;
        }

        if(index == weight.length){
            return 0;
        }

        if(dp[index][rest] != -1) {
            return dp[index][rest];
        }

        int next = processTwo(rest - weight[index], weight, value, index+1, dp);
        int ans1 = 0;
        if(next != -1){
            ans1 = value[index] + next;
        }
        int ans2 = processTwo(rest, weight, value, index+1, dp);
        int max = Math.max(ans1, ans2);
        dp[index][rest] = max;
        return max;
    }

    public static int maxValueThree(int capacity, int[] weight, int[] value){
        if(capacity < 0 || weight == null || value == null || weight.length == 0 || value.length == 0 || weight.length != value.length){
            return 0;
        }
        int N = weight.length;
        int[][] dp = new int[N+1][capacity+1];
        //直接赋值
        for (int i = N-1; i >= 0; i--) {
            for (int j = 0; j <= capacity; j++) {

                //i位置的值取
                int next = j - weight[i] < 0 ? -1 : dp[i+1][j-weight[i]];
                int ans1 = 0;
                if(next != -1){
                    ans1 = value[i] + next;
                }
                //i位置的值不取
                int ans2 = dp[i+1][j];
                //比较然后存值
                dp[i][j] = Math.max(ans1, ans2);
            }
        }

        return dp[0][capacity];
    }

    //生成两个数组返回
    public static int[][] generateArray(int maxSize, int maxValue){
        int size = (int)((maxSize + 1) * Math.random());
        int[][] arr = new int[2][size];
        for (int i = 0; i < size; i++) {
            arr[0][i] = (int)((maxValue + 1) * Math.random());
            arr[1][i] = (int)((maxValue + 1) * Math.random());
        }
        return arr;
    }



    public static void main(String[] args) {

        int testTime = 1000;
        int maxSize = 100;
        int maxValue = 100;
        for (int i = 0; i < testTime; i++) {
            int[][] array = generateArray(maxSize, maxValue);
            int capacity = (int)(100*(Math.random()));
            int one = maxValueOne(capacity, array[0], array[1]);
            int two = maxValueTwo(capacity, array[0], array[1]);
            int three = maxValueThree(capacity, array[0], array[1]);
            if(one != two || one != three){
                System.out.println("小伙子,有点问题,再改改!!!");
            }
        }
        System.out.println("真不错,perfect!!!");
    }
}

标签:index,背包,capacity,weight,int,value,length,动态,规划
From: https://blog.51cto.com/u_14291296/6237884

相关文章

  • 线性规划
    线性规划问题线性规划问题指的是:给定若干个变量,这些变量满足一系列线性等式关系或线性不等式关系,要在满足这些关系的前提下求出某个这些变量的线性函数的最大值或最小值。我们可以用“归约”的思想把线性规划问题的描述统一为标准的形式,称为“标准型”:首先我们可以把问题归约为......
  • 背包问题
    背包问题是一种组合优化的NP完全问题.问题可以描述为:给定一组物品,每种物品都有自己的体积和价值,在限定的总体积内,我们如何选择,才能使得物品的总价值最高.背包九讲①01背包问题有N件物品和一个容量是V的背包,每件物品只能使用一次第i件物品的体积是vi......
  • 动态k小
    题目: 这道题目十分简单,只要用大根堆维护前k小的数字即可,用大根堆是因为方便输出(用小根堆需要输出堆底),前k个先单独输入,不输出(第k个除外,单独输出),之后k+1~n如果输入进来的数字比堆顶大,直接跳过,否则先把原堆顶弹出再推入输入进来的数字,每一次输出堆顶即可。程序:#include<bits/s......
  • 2023-04-29 动态规划介绍
    2023-04-29动态规划介绍动态规划是运筹学课程的一部分多阶段决策问题有一类活动的过程,可以分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果当然,每个阶段的决策的选取不是任意确定的,它依赖于当前的状态,又会影响以后的发展如下图,①......
  • 【完全背包的排列问题】NO377. 组合总和 Ⅳ
    [完全背包排列问题]377.组合总和Ⅳ给你一个由不同整数组成的数组nums,和一个目标整数target。请你从nums中找出并返回总和为target的元素组合的个数。题目数据保证答案符合32位整数范围。示例1:输入:nums=[1,2,3],target=4输出:7解释:所有可能的组合为:(1,......
  • 动态增加表单方法--ff/ie
    ---------------------增加方法----------------------------<h3><center>批量增加评论</center></h3><BR><formaction=""method="post"οnsubmit="returncheck_form();"><inputtype="button"va......
  • Java 项目中一种简单的动态修改配置即时生效的方式 WatchService
    这种方式仅适合于比较小的项目,例如只有一两台服务器,而且配置文件是可以直接修改的。例如Springmvc以war包的形式部署,可以直接修改resources中的配置文件。如果是Springboot项目,还想用这种方式的话,就要引用一个外部可以编辑的文件,比如一个固定的目录,因为springboot大多......
  • Spring AOP 和 动态代理技术
     AOP是什么东西首先来说AOP并不是Spring框架的核心技术之一,AOP全称AspectOrientProgramming,即面向切面的编程。其要解决的问题就是在不改变源代码的情况下,实现对逻辑功能的修改。常用的场景包括记录日志、异常处理、性能监控、安全控制(例如拦截器)等,总结起来就是,凡是想对......
  • 【专栏精选】实战:动态配置图片
    本文节选自洪流学堂公众号技术专栏《大话Unity2019》,未经允许不可转载。洪流学堂公众号回复专栏,查看更多专栏文章。洪流学堂,让你快人几步。你好,我是郑洪智。小新:“大智,最近我在做一个虚拟展厅的demo,你说我怎么最大程度提高这个程度的扩展性呢?最好图片和文字说明是可以动态替换的。......
  • [独家放送]Unity2020规划预览,可视化编程又双叒叕来了!
    你好,我是你的技术探路者郑洪智,你可以叫我大智。欢迎一起进入2020年,在新的一年里Unity有什么大动作呢?本文带你速览你最关心的Unity2020的核心功能!你最可能关心的功能有哪些呢?Unity2019.3在哪里???(乱入)下面从四个方面来看Unity有哪些更新:核心功能和性能更多的DOTS(Data-OrientedTechSt......