贪心算法
- 贪心算法的核心思路:
只顾眼前最优,以求得全局的最优,所以我们在设计贪心的时候就要思考如何或者说能否通过眼前的利益获得最大的利益 - 但是要注意:
贪心算法并不一定是给出的最佳答案,在某些特殊情况下只能给出近似值,因此贪心算法追求的是方便快捷并不能保证100%正确,因为这样也符合我们平时生活中的一些"贪心"目的 - 若是要实现100%正确就要使用动态规划算法,这个后面有计划讲,今天主讲贪心算法
找零钱
- 问题描述:
中华人民共和国的纸币金额为100 50 20 10 5 1 现在每张货币都有N张, 输入要找的零钱, 输出找的最小张数的方案 - 解决方案:
既然是贪心算法, 我先从100开始对比, 如果零钱大于100就取n张, 然后将剩余要找的零钱递归处理,
import java.util.Scanner;
//贪心算法
public class Test {
private static int[] moneyKind = new int[] {1, 5, 10, 20, 50, 100};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int money = scanner.nextInt();
greedyFunc(money, moneyKind.length - 1);
}
}
private static void greedyFunc(int money, int index) {
//防止下标越界
if (index < 0) {
return;
}
//如果此时需要的钱是0就直接返回
if (money == 0) {
return;
}
//如果此时需要的钱比此时的面值小,就往下一个面值递归
if (money < moneyKind[index]) {
greedyFunc(money, index - 1);
} else {
int num = money / moneyKind[index];
System.out.println("需要:" + moneyKind[index] + "元" + num + "张");
money = money - num * moneyKind[index];
greedyFunc(money, index - 1);
}
}
}
测试:
13
需要:10元1张
需要:1元3张
121
需要:100元1张
需要:20元1张
需要:1元1张
神奇的口袋
- 问题描述:
链接:https://www.nowcoder.com/questionTerminal/9aaea0b82623466a8b29a9f1a00b5d35
来源:牛客网
有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a1,a2……an。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。
- 解决方案:
使用贪心算法,每次取下标为n的物品, 看他是否可以得到我们想要的利益, 如果最后w(w为我们需要的体积)==0 就说明在第一次取下标为n的物品可以得到我们想要的结果,所以count++ 结束此次递归 结束递归的条件还要如果算下需要的体积w<0 结束循环 或者 物品取完了 需要的体积还是大于0 也结束循环
import java.util.*;
public class Main{
private static int count = 0;
private static int[] nums;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while(scan.hasNext()) {
int n = scan.nextInt();
nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = scan.nextInt();
}
greedyFunc(40, n - 1);
System.out.println(count);
}
}
private static void greedyFunc(int w, int n) {
//w的需要的体积,如果小于0就退出. 如果此时访问的下标为小于0了,但是需要的体积还是正数就也要退出
if ((w > 0 && n < 0) || w < 0) {
return;
}
//需要的体积为0 就结束递归count++
if (w == 0) {
count++;
return;
}
//看当前可以不可以得到最优结果
greedyFunc(w - nums[n], n - 1);
//走向下一个下标,看可不可以得到最优结果
greedyFunc(w, n - 1);
}
}
- 举个例子说明一下为什么贪心算法有时候不是最优解需要借助动态规划来实现最优
例如 类似第一题的找零钱问题 如果面值是7 5 1
此时我们还是找零钱还是要求找的张数最小
如果我们使用第一题的解决方法 输出的会是 一张7元 和 2 张1元
但是实际正确答案应该是俩张5元
所以如果要达到100%正确结果就要使用动态规划.