贪心算法--堆--成本与利润

输入:

参数1, 正数数组costs

参数2, 正数数组profits

参数3,正数k

参数4, 正数m


costs[i]表示i号项目的花费

profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润)

k表示你不能并行、 只能串行的最多做k个项目

m表示你初始的资金

说明: 你每做完一个项目, 马上获得的收益, 可以支持你去做下一个 项目。
输出: 你最后获得的最大钱数。

 

将每个项目的成本和利润放到一起,

然后准备一个大根堆,一个小根堆

首先小根堆:按照成本的大小排序,然后将成本小于w的项目全部弹出,加入到大根堆中(大根堆是按照利润的大小进行排序)

然后将大根堆中的顶点值弹出,即是本次选择的项目,然后本金m增加,k减少一次,继续下一次

如果小根堆不能弹出项目(成本大于现在的本金)时,继续从大根堆弹出项目。进行下一次,直到k为0

 

public class IPO {

    public static class Item {
        private int cost;
        private int profit;

        public Item(int cost, int profit){
            this.cost = cost;
            this.profit = profit;
        }
    }

    //按照最小成本构建的小根堆中
    public static class MinheapComparator implements Comparator<Item>{

        @Override
        public int compare(Item o1, Item o2) {
            return o1.cost - o2.cost;
        }
    }

    //按照最大收益构建的大根堆中
    public static class MaxheapComparator implements Comparator<Item>{

        @Override
        public int compare(Item o1, Item o2) {
            return o2.profit - o1.profit;
        }
    }

    public int maxProfit(int[] costs, int[] profits, int k, int m){
        if(costs == null || profits == null || costs.length != profits.length || k <= 0) return 0;

        //用来将项目放到一个按照最小成本构建的小根堆中
        PriorityQueue<Item> itemsByMinCost = new PriorityQueue<>( new MinheapComparator() );
        for(int i = 0; i < costs.length; i++){
            itemsByMinCost.add(new Item(costs[i], profits[i]));
        }

        //用来盛放按照当前资金可以承受的范围内的项目,且按照最大收益构建的大根堆中(从小根堆中弹出的)
        PriorityQueue<Item> itemsByMaxProfit = new PriorityQueue<>( new MaxheapComparator() );

        //错误的循环,下面那个是对的
        //这个判断条件有问题,当小根堆中的元素全部入大根堆的队列中,且还未达到k时,此时就会跳出循环,这样是不对的
        while(itemsByMinCost.size() > 0 && k > 0){
            while(itemsByMinCost.peek().cost <= m) {
                itemsByMaxProfit.add( itemsByMinCost.poll() );
            }

            if(itemsByMaxProfit.isEmpty() && itemsByMinCost.peek().cost > m) break;

            if(itemsByMaxProfit.size() > 0){
                m += itemsByMaxProfit.poll().profit;
                k--;
            }
        }

        //这个循环判断条件是对的,上面那个是不对的
        for(int i = 0; i < k; i++){
            while(!itemsByMaxProfit.isEmpty() && itemsByMinCost.peek().cost <= m){
                itemsByMaxProfit.add(itemsByMinCost.poll());
            }

            
            if(itemsByMaxProfit.isEmpty()) break;

            m += itemsByMaxProfit.poll().profit;

        }
        return m;
    }
}

  

posted @ 2018-04-27 15:17  SkyeAngel  阅读(511)  评论(0编辑  收藏  举报