贪心算法之背包问题

贪心算法之背包问题

背包问题是算法的经典问题,分为部分背包和0-1背包,主要区别如下:

部分背包:某件物品是一堆,可以带走其一部分

0-1背包:对于某件物品,要么被带走(选择了它),要么不被带走(没有选择它),不存在只带走一部分的情况。

部分背包问题

假设一共有N件物品,第 i 件物品的价值为 Vi ,重量为Wi,一个小偷有一个最多只能装下重量为W的背包,他希望带走的物品越有价值越好,可以带走某件物品的一部分,请问:他应该选择哪些物品?

假设背包可容纳50Kg的重量,物品信息如下表:

将物品按单位重量 所具有的价值排序。总是优先选择单位重量下价值最大的物品,单位重量的价值排序:物品A > 物品B > 物品C

因此,我们尽可能地多拿物品A,直到将物品1拿完之后,才去拿物品B,然后是物品C 可以只拿一部分…..

public class Bag {
    /**
     * 最大承重
     */
    private double max=0;

    private void getMaxValue(Goods[] goodsList){
        // 对物品按照价值排序从高到低
        Arrays.sort(goodsList, Comparator.comparingDouble((Goods goods) -> goods.value).reversed());

        //当前总重
        double sumWeight=0;

        // 取出价值最高的
        for(int i=0;i<goodsList.length;i++){
            sumWeight+=goodsList[i].weight;
            if(sumWeight<=max){
                System.out.println(goodsList[i].name+"取"+goodsList[i].weight+"kg");
            }
            else{
                System.out.println(goodsList[i].name+"取"+(max-(sumWeight-goodsList[i].weight))+"kg");
                return ;
            }
        }
    }


    public static void main(String[] args) {
        Bag bag=new Bag();
        Goods g1=new Goods("A",10,60);
        Goods g2=new Goods("B",20,100);
        Goods g3=new Goods("C",30,120);
        Goods[] goods={g1,g2,g3};
        bag.max=50;
        bag.getMaxValue(goods);
    }

}

public class Goods {
    /**
     * 名称
     */
    String name;
    /**
     * 重量
     */
    double weight;
    /**
     * 价格
     */
    double price;
    /**
     * 价值
     */
    double value;

    public Goods(String name, double weight, double price) {
        this.name = name;
        this.weight = weight;
        this.price = price;
        this.value=price/weight;
    }
}
0-1背包问题

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

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

分析:

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

w[1]=2,v[1]=6

w[2]=2,v[2]=3

w[3]=6,v[3]=5

w[4]=5,v[4]=4

w[5]=4,v[5]=6

dp数组的计算结果如下表:

i:选择i件物品 j:最大承重
public class Bag01 {
    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(max <= 0){
            return 0;
        }
        int dp[][] = new int[values.length+1][max+1];
        for (int i = 1; i <= values.length; i++) {
            for (int j = 1; j <= max; j++) {
                // 选中的物品重量
                int selectedWeight = weights[i - 1];
                // 如果选择的物品重量超过最大承重
                if(selectedWeight > j){
                    // 最大的价值 = 上一轮的最大价值(不选择该物品)
                    dp[i][j] = dp[i-1][j];
                }else {
                    // 选择物品
                    // 选择该物品之后的价值 与 不选择该物品的价值(上一轮的最大价值)做比较,找出最大值
                    dp[i][j] = Math.max(dp[i-1][j],values[i-1]+dp[i-1][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));
    }
}
  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值