算法练习day14——190402(贪心:切金条、做项目、会议室安排)
1. 切金條
一塊金條切成兩半,是需要花費和長度數值一樣的銅板的。
比如長度為20的金條, 不管切成長度多大的兩半,都要花費20個銅板。
一群人想整分整塊金條, 怎么分最省銅板?
例如,給定數組{10,20,30}, 代表一共三個人, 整塊金條長度為10+20+30=60。金條要分成10,20,30三個部分。 如果, 先把長度60的金條分成10和50, 花費60。再把長度50的金條分成20和30,花費50。一共花費110銅板。但是如果先把長度60的金條分成30和30,花費60再把長度30金條分成10和20,花費30一共花費90銅板。
輸入一個數組, 返回分割的最小代價。
1.1 分析
這是一個標準的哈夫曼問題:兩個葉節點合并的時候,代價就是葉節點之和。
給定10,20,30,構成一個數,使得所有非葉節點之和最小。
解題思路:
給定一組數:{1,2,6,4,3,7,1,8},然后將這組數構成一個小根堆。每次從小根堆中拿出兩個數。
第一次拿的肯定是兩個1。這兩個1生成一個節點,代價為2。然后把這個2扔回到小根堆中。
接著拿出兩個數:兩個2,這兩個2合并的代價為4,然后將4扔回到小根堆中。。。。
最終得到的結果:
貪心:在所有的數中總是拿兩個最小的。
此題中,切割的順序是根據形成的樹由上到下的。
1.2 代碼實現
public static int lessMoney(int[] arr) {PriorityQueue<Integer> pQ = new PriorityQueue<>();//系統實現的堆for (int i = 0; i < arr.length; i++) {pQ.add(arr[i]);//所有的數入堆}int sum = 0;int cur = 0;while (pQ.size() > 1) {//堆中元素只有一個時,停止cur = pQ.poll() + pQ.poll();//每次取兩個,求和即為代價sum += cur;//當前和累加pQ.add(cur);//將和放回堆中}return sum; }2. 項目收益最大
輸入:
- 參數1, 正數數組costs;
- 參數2, 正數數組profits;
- 參數3,正數k;
- 參數4, 正數w;
- costs[i]:表示i號項目的花費;
- profits[i]:表示i號項目在扣除花費之后還能掙到的錢(利潤);
- k表示你不能并行、 只能串行的最多做k個項目,即一次只能做一個項目,只能做夠k個;
- w表示你初始的資金。
說明: 你每做完一個項目,馬上獲得的收益,可以支持你去做下一個項目。
輸出: 你最后獲得的最大錢數。
2.1 分析
將costs數組和profits數組合并為一個以項目為單位的數組:
[項目1(cost1,profit1),項目2(cost2,profit2),...]
然后根據這個項目數組,建立一個小根堆,花費最小的在頂部。
在小根堆中,依次彈出花費小于w的頭部。
將彈出的項目放入大根堆中,收益最大的在頂部。
然后選擇大根堆頂部的項目執行,此項目一定是所有可做項目中收益最大的。
做完這個項目后,資金變多為w'(增加了此項目的收益),然后繼續彈出小根堆中花費小于w'的頭部,放到大根堆中,依收益排序。
這樣一直做k個結束。
2.2 舉例
2.3 代碼實現
import java.util.Comparator; import java.util.PriorityQueue;public class Code_03_IPO {public static class Node {//每個Node就是一個項目public int p;//收益public int c;//花費public Node(int p, int c) {this.p = p;this.c = c;}}public static class MinCostComparator implements Comparator<Node> {@Overridepublic int compare(Node o1, Node o2) {return o1.c - o2.c;}}public static class MaxProfitComparator implements Comparator<Node> {@Overridepublic int compare(Node o1, Node o2) {return o2.p - o1.p;}}public static int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) {Node[] nodes = new Node[Profits.length];for (int i = 0; i < Profits.length; i++) {//合并兩個數組,以項目為單位重建一個數組nodes[i] = new Node(Profits[i], Capital[i]);}PriorityQueue<Node> minCostQ = new PriorityQueue<>(new MinCostComparator());//根據花費建立的小根堆PriorityQueue<Node> maxProfitQ = new PriorityQueue<>(new MaxProfitComparator());//根據收益建立的大根堆for (int i = 0; i < nodes.length; i++) {minCostQ.add(nodes[i]);//建小根堆}for (int i = 0; i < k; i++) {//項目數小于kwhile (!minCostQ.isEmpty() && minCostQ.peek().c <= W) {maxProfitQ.add(minCostQ.poll());//彈出堆頂花費小于已有資金的項目,加入大根堆中}if (maxProfitQ.isEmpty()) {return W;//大根堆為空,即沒有可做的項目,返回總資金}W += maxProfitQ.poll().p;//執行大根堆堆頂的任務,增加總資金}return W;} }3.會議室安排
一些項目要占用一個會議室宣講, 會議室不能同時容納兩個項目的宣講。 給你每一個項目開始的時間和結束的時間(給你一個數組, 里面 是一個個具體的項目), 你來安排宣講的日程, 要求會議室進行的宣講的場次最多。 返回這個最多的宣講場次。
3.1 分析
貪心策略
3.2 代碼實現
import java.util.Arrays; import java.util.Comparator;public class BestArrange {public static class Program {public int start;public int end;public Program(int start, int end) {this.start = start;this.end = end;}}public static class ProgramComparator implements Comparator<Program> {@Overridepublic int compare(Program o1, Program o2) {return o1.end - o2.end;//結束時間早的安排在前面}}public static int bestArrange(Program[] programs, int start) {Arrays.sort(programs, new ProgramComparator());int result = 0;//完成的項目數for (int i = 0; i < programs.length; i++) {if (start <= programs[i].start) {//開始時間晚于給定的時間,則可以開始這個項目result++;start = programs[i].end;//將下一次開始時間設為當前已完成的項目結束時的時間}}return result;} } 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的算法练习day14——190402(贪心:切金条、做项目、会议室安排)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法练习day13——190401(前缀
- 下一篇: 算法练习day15——190403(简介