java贪心算法经典案例之项目利润最大问题

1、问题描述

输入:

正数数组costs
正数数组profits
正数k
正数m

含义:

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

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

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

m表示你初始的资金

说明:

你每做完一个项目,马上获得的收益,可以支持你去做下一个项目。

输出:

你最后获得的最大钱数。

2、问题分析

该问题很明显是一个贪心相关的问题,我们每次做项目的时候都选择项目成本在我的启动资金之内,并且利润最大的项目来做,这样是不是就做到了项目的利润最大化。

这里我们考虑使用两个堆来完成该贪心算法:一个大根堆(按项目利润组织)一个小根堆(按项目花费组织的)

①、首先将每个项目的启动资金(花费)和该项目的利润组成一个个的节点

②、将第一步组成的节点添加到一个小根堆里(添加完成后该小根堆就不动了,仅供每次从这个小根堆里挑选项目)。

③、每次挑一个在我们启动资金范围内且利润最大的项目。最多做k个项目,每次挑一个项目做,则我们需要挑的项目一定是花费在我们启动资金以内,并且他的利润一定是最大的。所以我们每次挑项目的时候:

1、首先根据我们的现有启动资金,从小根堆里挑选出所有项目成本小于我们的启动资金的项目。

2、将挑出来的项目全部放入到一个大根堆里(按利润组织的)

3、然后从大根堆里拿出堆顶项目(该项目就是满足项目成本在启动资金内,且利润最大的项目)

4、累加上面的项目所获得的利润。继续挑选下一个项目

3、代码实现

/**
 * 贪心算法求做项目最大利润问题
 *
 * @param k       最多能做的项目数量
 * @param w       启动资金
 * @param profits 每个项目的利润
 * @param capital 每个项目的成本
 * @return: int
 */
public static int findMaximizedCapital(final int k, int w, final int[] profits, final int[] capital) {

    // 小根堆,按照每个项目的最小花费(成本)构建成小根堆
    final PriorityQueue<Node> minCostQueue = new PriorityQueue<>();
    // 大根堆,按照每个项目的利润构建成一个大根堆
    final PriorityQueue<Node> maxProfitQueue = new PriorityQueue<>();

    // 先将每个项目的成本和利润组织为一个个的节点并放入到小根堆中
    for (int i = 0; i < profits.length; i++) {
        minCostQueue.add(new Node(profits[i], capital[i]));
    }

    // 开始做项目,每次循环代表做一个项目
    for (int i = 0; i < k; i++) {

        // 取出我当前启动资金能做的所有项目(即:项目成本小于我的启动资金的项目),放入到大根堆中
        // 注意这里peek和poll的区别,peek 不会删除元素,poll 会删除元素
        while (!minCostQueue.isEmpty() && minCostQueue.peek().cost <= w) {
            maxProfitQueue.add(minCostQueue.poll());
        }

        // 这里需要特别注意,很容易被忽视掉
        // 如果 maxProfitQueue 为空,则表示按照当前的启动资金,已经没有办法从小根堆(minCostQueue)里取出任何一个项目来做了
        if (maxProfitQueue.isEmpty()) {
            return w;
        }

        // 每次挑一个项目成本在我启动范围之内,并且利润最大的项目做
        final Node project = maxProfitQueue.poll();
        // 每个项目做完后,启动资金增加
        w = w + project.profit;
    }

    return w;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值