背包问题详解

背包问题主要分为0-1背包、完全背包、多重背包和分组背包问题。

图源:代码随想录 (programmercarl.com)

0-1 背包

问题描述:有一个容量为bagsize的背包,要从若干个重量为weight[i]、价值为value[i]物品中选取,使其总价值最大。

二维数组与一维数组遍历顺序不同的原因

二维数组

package TEST;
import java.util.Scanner;
//0-1背包问题二维数组
class test{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String[] str=sc.nextLine().split(" ");
        int bagsize=Integer.parseInt(str[1]);
        String[] sweight=sc.nextLine().split(" ");
        int[] weight=new int[sweight.length];
        for(int i=0;i<weight.length;i++){
            weight[i]=Integer.parseInt(sweight[i]);
        }
        String[] svalue=sc.nextLine().split(" ");
        int[] value=new int[svalue.length];
        for(int i=0;i<value.length;i++){
            value[i]=Integer.parseInt(svalue[i]);
        }
        System.out.println(testWeightBagProblem(weight,value,bagsize));
    }
    public static int testWeightBagProblem(int[] weight,int[] value,int bagsize){
        //1.含义dp[i][j]意味着0到i的背包随意选择满足容量为j最大的价值
        //2.递推公式:dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
        //3.初始化dp[i][0]=0(容量为0时价值为0),dp[0][小于weight[0]]=0,dp[0][大于等于weight[0]]=weight[i];
        //4.遍历顺序层数 既可以先遍历背包数,后遍历重量;也可以先遍历重量,后遍历背包数
        int[][] dp=new int[weight.length][bagsize+1];
        //因为数组初始化默认是0,故可以不写
//        for(int i=0;i<weight.length;i++){
//            dp[i][0]=0;
//        }
//        for(int j=0;j<weight[0];j++){
//            dp[0][j]=0;
//        }
        for(int j=weight[0];j<bagsize+1;j++){
            dp[0][j]=value[0];
        }
        for(int i=1;i<dp.length;i++){
            for(int j=1;j<dp[i].length;j++){
                if(j-weight[i]<0){
                    //当前当前背包容量不能放i,最大值等于dp[i-1][j]
                    dp[i][j]=dp[i-1][j];
                }else{
                    //当前当前背包容量可以放i,最大值在放与不放之间去最大值
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
                }
            }
        }
        return dp[weight.length-1][bagsize];
    }
}

 一维数组

package TEST;
import java.util.Scanner;
//0-1背包问题一维数组
class test2{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String[] str=sc.nextLine().split(" ");
        int bagsize=Integer.parseInt(str[1]);
        String[] sweight=sc.nextLine().split(" ");
        int[] weight=new int[sweight.length];
        for(int i=0;i<weight.length;i++){
            weight[i]=Integer.parseInt(sweight[i]);
        }
        String[] svalue=sc.nextLine().split(" ");
        int[] value=new int[svalue.length];
        for(int i=0;i<value.length;i++){
            value[i]=Integer.parseInt(svalue[i]);
        }
        System.out.println(testWeightBagProblem(weight,value,bagsize));
    }
    public static int testWeightBagProblem(int[] weight,int[] value,int bagsize){
        //1.含义dp[j]意味着0到i的背包随意选择满足容量为j最大的价值
        //2.递推公式:dp[j]=Math.max(dp[j],dp[j-weight[i]]+value[i])
        //3.初始化dp[j]=0;
        //4.遍历顺序层数 只可以先遍历背包数,后遍历重量,而且遍历重量从后往前遍历,防止重复选入背包
        int[] dp=new int[bagsize+1];
        for(int i=0;i<weight.length;i++){
            //遍历顺序从后往前,避免重复选,如果从前往后则是完全背包问题
            for(int j=bagsize;j>=0;j--){
                    if(j-weight[i]<0){
                        System.out.print(dp[j]+" ");
                    }else{
                        dp[j]=Math.max(dp[j],dp[j-weight[i]]+value[i]);
                        System.out.print(dp[j]+" ");
                    }
                System.out.println();
                }
         }
        return dp[bagsize];
    }
}



完全背包

与0-1背包不同的地方在于既可以先遍历物品后遍历背包,也可以先遍历背包后遍历物品,对于i,j都是从前向后遍历的

组合:先遍历物品后遍历背包,例题:518. 零钱兑换 II - 力扣(LeetCode)

排列:先遍历背包后遍历物品,例题:377. 组合总和 Ⅳ - 力扣(LeetCode)

多重背包

在01背包基础上,多循环一次背包个数。

package TEST;
//多重背包问题
class test{
    public static void main(String[] args){
        //dp[j]表示容量为i情况下,背包所能放的最大价值
        //递推公式dp[j]=Math.max(dp[j],dp[j-k*weight[i]]+k*value[i]);
        //初始化dp[0]=0
        //先物品后背包,背包从后往前遍历,加一次物品个数的循环
        int[] weight = new int[] {1, 3, 4};
        int[] value = new int[] {15, 20, 30};
        int[] nums = new int[] {2, 3, 2};
        int bagWeight = 10;
        int[] dp=new int[bagWeight+1];
        for(int i=0;i<weight.length;i++){ //先遍历物品
            for(int j=bagWeight;j>weight[i];j--){ //后遍历背包
                for(int k=1;k<=nums[i]&&j>=k*weight[i];k++){ //再遍历物品个数,从1开始到nums[i]结束
                    dp[j]=Math.max(dp[j],dp[j-k*weight[i]]+k*value[i]);
                }
            }
        }
        System.out.println(dp[bagWeight]);
    }

}

代码随想录 (programmercarl.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值