贪心思想就是保证每次操作都是局部最优的,并且最后得到的结果是全局最优的。不一定要证明最后就是最优的。
第一个问题
一块金条切成两半, 是需要花费和长度数值一样的铜板的。 比如长度为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)把求解的问题分成若干个子问题;
2)判断子问题之间是否具备无后效性;
3)对每一子问题求解,得到子问题的局部最优解;
4)把子问题的局部最优解合成原来问题的一个解;
解决分金条问题:
1)把整个问题逆过程来,有许多小块,每次合并需要两个相加的cost,如10和20合并需要cost30。
2)各个子过程无关
3)每一次合并,我都希望合并最小的两个
4)最后把所有cost相加
注意:比较器的使用,人为的定义比较器,确定优先级队列顺序(以哪个值排序、升序还是降序)
public static class MinheapComparator implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;//小根堆
}
}
public static int lessMoney(int[] arr) {
int sum = 0;
PriorityQueue<Integer> pQ = new PriorityQueue<>(new MinheapComparator());
for(int i = 0; i < arr.length; i++) {
pQ.add(arr[i]);
}
int cur = 0;
while(pQ.size() > 1) {
cur = pQ.poll() + pQ.poll();
pQ.add(cur);
sum += cur;
}
return sum;
}
第二个问题:做k个项目后获得的最大钱数,有许多项目,每个项目有利润和成本两个数据,每次只能做一个,做完不能再做。
1)分割子问题:每一次选择一个项目来做
2)无后效性
3)贪心求解:每一次选择都是可选里面利润最大的
4)合并总利润
package class_07;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Code_03_IPO {
public static class 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> {
@Override
public int compare(Node o1, Node o2) {
return o1.c - o2.c;
}
}
public static class MaxProfitComparator implements Comparator<Node> {
@Override
public 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++) {
//还有可做的项目
while (!minCostQ.isEmpty() && minCostQ.peek().c <= W) {
maxProfitQ.add(minCostQ.poll());
}
//大根堆的里面还有可做的项目
if (maxProfitQ.isEmpty()) {
return W;
}
//加上利润
W += maxProfitQ.poll().p;
}
return W;
}
}