算法之 --- 背包01版+ 挖金矿问题

背包问题:

有一个包和n个物品,包的容量为m,每个物品都有各自的体积和价值,问当从这n个物品中选择多个物品放在包里而物品体积总数不超过包的容量m时,能够得到的最大价值是多少?
[对于每个物品不可以取多次,最多只能取一次,之所以叫做01背包,0表示不取,1表示取]

挖金矿问题

有一个国家,所有的国民都非常老实憨厚,某天他们在自己的国家发现了十座金矿,并且这十座金矿在地图上排成一条直线,国王知道这个消息后非常高兴,他希望能够把这些金子都挖出来造福国民,首先他把这些金矿按照在地图上的位置从西至东进行编号,依次为0、1、2、3、4、5、6、7、8、9,然后他命令他的手下去对每一座金矿进行勘测,以便知道挖取每一座金矿需要多少人力以及每座金矿能够挖出多少金子,然后动员国民都来挖金子。

这两个问题其实都属于一种问题,每一个物品/金矿都只有两种可能,放与不放(挖与不挖)

以金矿问题为例:

  • 当开始挖第一个编号为0 的金矿的时候:
    • 如果挖 0 金矿,剩余金矿可以获取最大多少利润
    • 如果不挖 0 金矿,剩余金矿可以获取最大多少利润
  • 依次类推,挖第二个编号为1的金矿的时候:
    • 如果挖 1 金矿,剩余金矿可以获取最大多少利润
    • 如果不挖 1 金矿,剩余金矿可以获取最大多少利润
  • … …
  • … …
  • 当挖第 9 个金矿的时候,你可以确定知道 最大利润是多少,然后反推向上,就知道最大利润是多少了

金矿代码附上:

public class KingGold {


    private static int maxGoldNum = 0;


    private int peopleTotal; //总共可以使用的工人数量


    private int[] goldNum;//每座金矿能够挖出的最大金子的数量

    private int[] peopleNeeded;//每座金矿所需要的工人数量


    public static void main(String[] args) {

        try {
            KingGold dp = new KingGold();
            int x = dp.maxGold(dp.peopleTotal, dp.goldNum.length - 1);
            System.out.println(x);
        } catch (Exception e) {
            System.err.println(e);
        }


    }

    public KingGold() {
        this.peopleTotal = 100;
        this.peopleNeeded = new int[]{32, 77, 29};
        this.goldNum = new int[]{92, 22, 87};

    }

    public int maxGold(int peopleLeft, int mineNum) {

        //最后一座金矿的可采金量
        if (mineNum == 0) {
            if (peopleLeft >= this.peopleNeeded[0]) {
                maxGoldNum = this.goldNum[0];
                return maxGoldNum;
            } else {
                maxGoldNum = 0;
                return maxGoldNum;
            }
        } else if (peopleLeft > this.peopleNeeded[mineNum]) {

            //获取下一级 金矿数量
            int nexGold = this.maxGold(peopleLeft - this.peopleNeeded[mineNum], mineNum - 1);

            //获取总金矿数量 下一级 + 这级金矿
            int sumGold = nexGold + this.goldNum[mineNum];

            //不获取这级金矿  直接获取下一个金矿数量
            int nexGoldNew = this.maxGold(peopleLeft, mineNum - 1);

            //比较种金矿总量
            if (sumGold > nexGoldNew) {
                maxGoldNum = sumGold;
            } else {
                maxGoldNum = nexGoldNew;
            }

        } else {
            //如果人不够采这个金矿,直接挖下一个金矿
            maxGoldNum = this.maxGold(peopleLeft, mineNum - 1);
        }
        return maxGoldNum;
    }


}

背包代码附上:

@Data
public class Package01 {




    private Integer packageSpace;

    private List<Integer> itemSpaceList;

    private List<Integer> itemPrice;


    private Integer maxItemPrice;




    public Package01(Integer packageSpace,List<Integer> itemSpaceList,List<Integer> itemPrice){
        this.packageSpace = packageSpace;
        this.itemSpaceList = itemSpaceList;
        this.itemPrice = itemPrice;
    }


    public static void main(String[] args) {

        Package01 package01 = new Package01(100, Lists.newArrayList(45,23,816,12),Lists.newArrayList(70,80,10,40));


        Integer maxItemPrice = package01.getMaxItemPrice(package01.getPackageSpace(), package01.getItemSpaceList().size() - 1);

        System.out.println(maxItemPrice);


    }


    public Integer getMaxItemPrice(Integer packageSpace,Integer nextItemId){


        //如果是最后一个
        if(nextItemId == 0){

            if(packageSpace > this.itemSpaceList.get(nextItemId)){
                return this.itemPrice.get(nextItemId);
            }else{
                return 0;
            }
        }

        //如果背包空间充足
        if(packageSpace > this.itemSpaceList.get(nextItemId)){

            //这个东西放入背包
            Integer price = itemPrice.get(nextItemId);
            //下面的价值
            Integer nextPrice = this.getMaxItemPrice(packageSpace - this.itemSpaceList.get(nextItemId), nextItemId - 1);


            //这个东西不放入背包
            Integer otherPrice = this.getMaxItemPrice(packageSpace, nextItemId - 1);


            //比较价值
            if(price+nextPrice > otherPrice){
                return price+nextPrice;
            }else{
                return otherPrice;
            }

        }else{
            //背包空间不够,直接获取剩余商品价值
            return this.getMaxItemPrice(packageSpace, nextItemId - 1);

        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值