贪心算法的实际应用

1.问题:给定初始资金,有N个项目,每个项目有成本和纯利润,在其中选取k个项目,求获得的最大利润。

例如:有项目(花费,利润):[1,2],[1, 4],[5, 4],[5,6],初始资金是1,可做最大项目是2个。

那么选取符合成本的项目[1,2], [1, 4],选取利润大的项目[1,4],得到总资金5。然后在[5, 4],[5,6]选取[5,6]得到最后的总资金11。

解:

  • 根据花费建立比较器,将项目存放到小根堆中,根据利润建立比较器,建立大根堆。
  • 循环k次,将花费小于等于总资金的项目放入大根堆,取出 大根堆的项目,累加利润,大根堆为空或者循环完k次结束计算。
    /**
     * 根据项目的花费和利润,在初始资金和限制max项目数的情况下,获得最大利润
     * @param data
     * @param initMoney
     * @param maxProject
     * @return
     */
    public static int maxMoney(ProjectInfo[] data, int initMoney, Integer maxProject) {
        PriorityQueue<ProjectInfo> minCostQueue = new PriorityQueue<>(Comparator.comparingInt(o -> o.cost));
        PriorityQueue<ProjectInfo> mxProfitsQueue = new PriorityQueue<>((o1,o2) -> o2.profits - o1.profits);
        //小根堆组织说有花费的项目
        minCostQueue.addAll(Arrays.asList(data));
        //循环挑选项目k次
        int sumMoney = initMoney;
        for (int i = 0; i < maxProject; i++) {
            //选取符合花费条件的项目
            while (!minCostQueue.isEmpty() && minCostQueue.peek().cost <= sumMoney) {
                mxProfitsQueue.add(minCostQueue.poll());
            }
            if (mxProfitsQueue.isEmpty()) {
                return sumMoney;
            }
            sumMoney += mxProfitsQueue.poll().profits;
        }
        return sumMoney;
    }

   @AllArgsConstructor
    public static class ProjectInfo {
        private Integer cost;
        private Integer profits;
    }

2. 问题:按数组划分金条,每次花费的为金条长度的代价,求最小花费。

例如:将金条按照[10,20,30]划分,那么总长度是60.那么可以采取的方案是:

60  -> 30,30  -> 10,20; 花费:60 + 10 + 20 = 90;

60 ->10, 50 -> 20,30; 花费: 60 + 20 + 30 = 110;

60 ->20, 40 -> 10,30; 花费:60 + 10 + 30 = 100;

可见按照第一种的方式成本是最小的。 

解:

  • 按照花费建立小顶堆,取出小顶堆的元素累加求和,得到最后的总花费;
    public static int lessMoney(Integer[] datas) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        queue.addAll(Arrays.asList(datas));
        int sum = 0;
        while (queue.size() > 1) {
            sum += queue.poll() + queue.poll();
            queue.add(sum);
        }
        return sum;
    }

问题:最优的方式安排会议

解:

  • 按照会议结束时间建立比较器,将会议放入小顶堆;
  • 循环所有会议,符合限制开始时间时结果加一,然后限制开始时间后移到当前会议的结束时间。

    //哪个会议的结束时间早就安排在前面
    public static int arrangeProject(Integer timePoint, Cnference[] cnferences) {
        int result = 0;
        Arrays.stream(cnferences).sorted();
        for (int i = 0; i < cnferences.length; i++) {
            if (timePoint <= cnferences[i].start) {
                result++;
                timePoint = cnferences[i].end;
            }
        }
        return result;
    }


  public static class Cnference implements Comparator<Cnference> {
        private Integer start;
        private Integer end;

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

        public Cnference(Integer start, Integer end) {
            this.start = start;
            this.end = end;
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知始行末

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值