背包问题(Java)动态规划

背包问题(Java)

自从七月开始参加各厂笔试以来,遇到过很多次背包问题,每次都做得不太好,故学习总结一下

背包问题总述

0-1背包

有N件物品和一个容量为V的背包,第i件物品消耗的容量为weight[i],价值为value[i],求解放入哪些物品可以使得背包中总价值最大。
注意:每件物品只有一件

多重背包

有N种物品和一个容量为V的背包,第i种物品最多有num[i]件可用,每件物品消耗的容量为weight[i],价值为value[i],求解入哪些物品可以使得背包中总价值最大。
注意:每件物品有其对应的件数

完全背包

有N种物品和一个容量为V的背包,每种物品都有无限件可用,第i件物品消耗的容量为weight[i],价值为value[i],求解放入哪些物品可以使得背包中总价值最大。
注意: 每件物品有无限件

1、0-1背包问题

遇到一个新的物品只需要考虑装还是不装,状态方程如下
dp[i][j]表示前i件物品能装入容量为j的背包中的物品价值总和的最大值

	if(weight[i-1] > j)
             dp[i][j] = dp[i-1][j];//如果装了第j件超出容量,则不装
    else
             dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i-1]]+value[i-1]);

具体代码如下:

/**
     * 0-1背包问题
     * @param V 背包容量
     * @param N 物品种类
     * @param weight 物品重量
     * @param value 物品价值
     * @return
     */
    public static int ZeroOnePack(int V,int N,int[] weight,int[] value){

        //初始化动态规划数组int
        int[][] dp = new int[N+1][V+1];
        //将dp[i][0]和dp[0][j]均置为0
        for(int i=1;i<N+1;i++){
            for(int j=1;j<V+1;j++){
                
                //由于weight和value数组下标都是从0开始,注意第i个物品的重量为weight[i-1],价值为value[i-1]
                if(weight[i-1] > j)//如果第i件物品的重量大于背包容量j,则不装入背包
                    dp[i][j] = dp[i-1][j];
                else//判断
                    dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-weight[i-1]]+value[i-1]);
            }
        }
      return dp[N][V];
      }

2、多重背包问题

需要额外考虑物品的数量问题

/**
     * 多重背包
     * 
     * @param args
     */
    public static int manyPack(int V,int N,int[] weight,int[] value,int[] num){
        //初始化动态规划数组
        int[][] dp = new int[N+1][V+1];
        for(int i=1;i<N+1;i++){
            for(int j=1;j<V+1;j++){
                if(weight[i-1] > j)
                    dp[i][j] = dp[i-1][j];
                else{
                    //考虑物品的件数限制
                    int maxV = Math.min(num[i-1],j/weight[i-1]);
                    for(int k=0;k<maxV+1;k++){
                        dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-k*weight[i-1]]+k*value[i-1]);
                    }
                }
            }
        }
        return dp[N][V];
    }

3、完全背包问题

/**
     * 完全背包
     * 思路分析:
     * 注意这里当考虑放入一个物品 i 时应当考虑还可能继续放入 i,
     * 因此这里是dp[i][j-weight[i]]+value[i], 而不是dp[i-1][j-weight[i]]+value[i]。
     * 放第i件物品。这里的处理和01背包有所不同,因为01背包的每个物品只能选择一个
     * *因此选择放第i件物品就意味着必须转移到dp[i-1][v-w[i]]这个状态;但是完全背包
     *问题不同,完全背包如果选择放第i件物品之后并不是转移到dp[i-1][v-w[i]]这个状态,
     *而是转移到dp[i][v-w[i]],这是因为每种物品可以放任意件(注意有容量的限制,因此
     *还是有限的),放了第i件物品后还可以继续放第i件物品,直到第二维的v-w[i]无法保
     *持大于等于0为止。
     * @param V
     * @param N
     * @param weight
     * @param value
     * @return
     */
    public static int completePack(int V,int N,int[] weight,int[] value){
        int[][] dp = new int[N+1][V+1];
        for(int i=1;i<N+1;i++){
            for(int j=1;j<V+1;j++){
                if(weight[i-1] > j)
                    dp[i][j] = dp[i-1][j];
                else
                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-weight[i-1]]+value[i-1]);
            }
        }
        returndp[N][V];
      }

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值