数据结构与算法--01背包问题

        有n件物品和一个最大承重为W的背包,每件物品的重量是w[i],价值是v[i] 在保证总重量不超过W的前提下,选择某些物品装入背包,背包的最大总价值是多少?

注意:每个物品只有一件,也就是每个物品只能选择0件或者1件

分析:

        假设:W=10,有5件物品,重量和价值如下:

重量价值
126
223
365
454
546

        dp数组的计算结果如下表

i\j012345678910
000000000000
1(w[1]=2, v[1]=6)00666666666
2(w[2]=2, v[2]=3)00669999999
3(w[3]=6, v[3]=5)00669999111114
4(w[4]=5, v[4]=4)006699910111314
5(w[5]=4, v[5]=6)0066991212121515
上图中 横轴 j表示 当前最大承重纵轴 i 表示 物品编号,产生的值则表示 当前最大总价值 

例如:当最大承重为 7 ,可选物品编号为 {1,2,3,4} 时,可选择的最大总价值为 10 

解决思路: 

        在01背包问题中,获取物品只存在 获取 或者 不获取 这两种可能性

根据我们上图罗列出来的表格来看

如果可以选择这一件物品的话 :j > w[i] 即:当前最大承重 > 当前物品重量

  • 如果不选择的话:dp(i, j) = dp(i - 1, j)
  • 如果选择了的话:dp(i, j) = v[i] + dp(i - 1, j - w[i])

两者取价值最大的数:Max(dp(i, j) = dp(i - 1, j), dp(i, j) = v[i] + dp(i - 1, j - w[i]))

如果不可以选择这件物品的话:j<w[i],  即:dp(i, j) = dp(i - 1, j)

代码实现:

public class Bag2 {
    
    public static int maxValue(int[] values, int[] weights, int max){
        
        if (values == null || values.length == 0){
            return 0;
        }
        
        if (weights == null || weights.length == 0){
            return 0;
        }
        
        if (values.length != weights.length || max <= 0){
            return 0;
        }
        
        //dp数组
        int[][] dp = new int[values.length + 1][max + 1];

        for (int i = 1; i <= values.length; i++) {
            for (int j = 1; j <= max; j++){
                //选择的物品超过最大承重
                if(j < weights[i - 1]){
                    //最大价值 = 上一轮最大价值
                    dp[i][j] = dp[i - 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], values[i - 1] + dp[i - 1][j - weights[i - 1]]);
                }
            }
        }
        return dp[values.length][max];
    }

    public static void main(String[] args) {
        int[] values={6,3,5,4,6};
        int[] weights={2,2,6,5,4};
        int max=10;
        System.out.println(maxValue(values,weights,max));
    }
    
}

时间复杂度为:O(i * j)

可以看出动态规划计算的值是 上次的某个值+这次的值,是一种以空间换时间的算法。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值