动态规划(dp背包问题)

基本题型(一):01背包问题(每一件物品可以拿一次或不拿)

题目详情:01背包-AcWing题库

普通的01背包(二维数组)[缺点:内存消耗大,优点:容易理解]

    //普通动态规划01背包问题(核心代码)
    //定义一个物品类来存储
    public static class Article{
        public int weight;
        public int value;

        public Article(){};

        public Article(int weight, int value) {
            this.weight = weight;
            this.value = value;
        }

    }    

    //普通二维(第i层的数据与第i-1层的数据有关)
    public static void get_dp_tow(int nums,int weight,Article[] articles){
        int dp[][]=new int[nums+1][weight+1];
        for (int i = 1; i <= nums ; i++) {
            for (int j = 1; j <=weight ; j++) {
                if(j<articles[i].weight){
                    dp[i][j]=dp[i-1][j];
                    continue;
                }
                dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-articles[i].weight]+articles[i].value);
            }
        }
        System.out.println(dp[nums][weight]);
    }

这是01背包的一维优化(改善了二维dp内存消耗大的问题)



    //dp二维背包的一维优化
    //动态规划的核心代码(动态转移方程)dp[j]=max(dp[j-weight]+value,dp[j])
    //内层循环从weight开始进行--的原因是保证每个物品都只相加一次

    public static void get_dp_one(int nums,int weight,Article[] articles){
        int[] dp=new int[weight+1];
        for (int i = 0; i < nums ; i++) {
            for (int j = weight; j >=articles[i].weight ; j--) {
                dp[j]=Math.max(dp[j-articles[i].weight]+articles[i].value,dp[j]);
            }
        }
        System.out.println(dp[weight]);
    }

基本题型(二):完全背包问题(每一件物品可以拿多次(次数不限))

题目详情:3. 完全背包问题 - AcWing题库

(二维与01背包相似)直接上一维优化

//核心代码   
 public static void Complete_bag(Article[] articles,int weight){
        int nums=articles.length;
        int[] dp=new int[weight+1];
        for (int i = 0; i < nums  ; i++) {
            for (int j = articles[i].weight; j <=weight ; j++) {
                dp[j]=Math.max(dp[j],dp[j-articles[i].weight]+articles[i].value);
            }
        }
        System.out.println(dp[weight]);
    }

*j的遍历顺序决定了是01背包还是完全背包(可以画图自行理解)

基本题型(三):完全背包问题(每一件物品的数量确定)

基于对上述题目的理解,不在写二维dp[][]直接上一维优化后的背包
题目详情:多重背包-AcWing题库

//这里建立物品为三个参数:value,weight,nums    
public static class Article{
        public int value;
        public int weight;
        public int nums;

        public Article(){};

        public Article(int value, int weight, int nums) {
            this.value = value;
            this.weight = weight;
            this.nums = nums;
        }
    }

//(解题思想)每一个物品的不同数量可以当作不同的物品进行求解

    public static void Multiple_bag(Article[] articles,int weight){
        int nums=articles.length;
        int[] dp=new int[weight+1];
        for (int i = 0; i < nums ; i++) {
            for (int j = weight; j >=articles[i].weight; j--) {
                for (int k = 1; k <= articles[i].nums; k++) {
                    if(j-k*articles[i].weight<0){
                        break;
                    }
                    dp[j]=Math.max(dp[j-k*articles[i].weight]+k*articles[i].value,dp[j]);
                }
            }
        }
        System.out.println(dp[weight]);
    }

*dp[j]的确定需要对每一件物品的不同数目时的状态进行遍历

*多重背包还有后续优化(不写了)(小编也不是很明白)

基本题型(四):混合背包问题(前三种背包的结合体)

如果前三种背包已经很明白,可以不用看......

题目详情:混合背包-AcWing题库

//背包定义(依旧是三个元素value,weight,nums)    
public static class Article{
        public int value;
        public int weight;
        public int nums;

        public Article(){};

        public Article(int value, int weight, int nums) {
            this.value = value;
            this.weight = weight;
            this.nums = nums;
        }
    }

//分类讨论每一个物品的类型,进行解题,与前三种背包一样(前三种理解好,这种就没意思了)
public static void Hybrid_bag(Article[] articles,int weight){
        int nums=articles.length;
        int[] dp=new int[weight+1];
        for (int i = 0; i < nums ; i++) {
            //这里重新回顾一下三种背包的写法
            if (articles[i].nums==-1){
                //走01背包
                for (int j = weight; j >=articles[i].weight ; j--) {
                    dp[j]=Math.max(dp[j-articles[i].weight]+articles[i].value,dp[j]);
                }
            }else if(articles[i].nums==0){
                //走完全背包
                for (int j = articles[i].weight; j <=weight ; j++) {
                    dp[j]=Math.max(dp[j],dp[j-articles[i].weight]+articles[i].value);
                }
            }else {
                //走多重背包
                for (int j = weight; j >= articles[i].weight; j--) {
                    for (int k = 1; k <=articles[i].nums ; k++) {
                        if(j-k*articles[i].weight<0){
                            break;
                        }else {
                            dp[j]=Math.max(dp[j],dp[j-k*articles[i].weight]+k*articles[i].value);
                        }
                    }
                }
            }
        }
        System.out.println(dp[weight]);
    }

*也可以直接调用之前写的函数(易)

基本题型(五):二维费用背包(限制条件变为两个)

题目详情:二维费用背包-AcWing题库

//1.生成物品类,三个成员变量(体积,质量,价值)
public static class Article{
        public int volume;
        public int weight;
        public int value;

        public Article(int volume, int weight, int value) {
            this.volume = volume;
            this.weight = weight;
            this.value = value;
        }
    }
//因为有两个限制条件所以(只能尽可能的优化到二维dp)
//其中dp[i][j]的含义时在i质量,j容积的条件下所能容纳的最大价值
    public static void Cost_bag(Article[] articles,int volume,int weight){
        int nums=articles.length;
        int[][] dp = new int[weight + 1][volume + 1];
        for (int i = 0; i < nums ; i++) {
            for (int j = weight; j >=articles[i].weight ; j--) {
                for (int k = volume; k >=articles[i].volume ; k--) {
                    dp[j][k]=Math.max(dp[j][k],dp[j-articles[i].weight][k-articles[i].volume]+articles[i].value);
                }
            }
        }
        System.out.println(dp[weight][volume]);
    }

*对于物品的限制条件越多,会导致dp数组的维度越高

基本题型(六):分组背包问题

题目详情:分组背包

//收取每一件物品的情况两个常量(weight和value)   
public static class Article{
        public int weight;
        public int value;

        public Article(int weight, int value) {
            this.weight = weight;
            this.value = value;
        }
    }

//收取每一个组的信息为(一个Article的数组)
public static class GroupArticle{
        Article[] articles;
        public GroupArticle(Article[] articles) {
            this.articles = articles;
        }
    }   

//分组背包的核心代码
 public static void Group_bag(GroupArticle[] groupArticles,int weight){

       //这里解释一下为什么Group=length-1
       //因为输入数据作者是从索引为1开始有n个元素,所以length=n+1
       //需要对length-1才能获取数字的个数n
       //下面的-1操作同理

        int Group=groupArticles.length-1;
        int[][] dp = new int[Group + 1][weight + 1];
        for (int i = 1; i <= Group ; i++) {
            //从articles中选取一个物品
            Article[] articles=groupArticles[i].articles;
            int nums=articles.length-1;
           //这里解释一下需要在每一个weight下来找到最合适的value值
            for (int j = 1; j <= weight ; j++) {
                dp[i][j]=dp[i-1][j];
                for (int k = 1; k <= nums ; k++) {
                    if(j-articles[k].weight>=0){
                        dp[i][j]=Math.max(dp[i][j],dp[i-1][j-articles[k].weight]+articles[k].value);
                    }
                }
            }
        }
        System.out.println(dp[Group][weight]);
    }

分组背包稍微有一点难,不理解的话可以跳过不看

暂时dp规划就更新到这里

后续.......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值