Chapter4——贪心算法及其应用

写在前面

    贪心算法是一个应用非常广泛的算法,由于我自己对贪心算法的认识也不够深刻,因此会比较偏重于从题目入手来理解和掌握贪心算法。


1.1 定义

    对于贪心算法的规范性定义可以参考维基百科:贪心法,下面是一段来自维基百科的定义:

贪心法,又称贪心算法、贪婪算法、或称贪婪法,是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。

    以上定义理解起来并不难,下面通过几道例题来对贪心算法展开分析。

1.2 例题分析

例题1(找零钱问题)

    小x买了个钱包,结果买完就没钱放了,一气之下将钱包搁置箱底,常常忘记带出来。但是没有钱包的话,纸币放在口袋里很不方便,容易乱,也不容易掉,所以每次有买什么东西的时候,他都会让收银员找给他最少张数的纸币。收银员忙于找零,经常没法顾及这个问题,所以求助会编程的你。
正如我们所知,纸币面值一般有1元,5元,10元,20元,50元,100元。
输入格式:

输入包含多组数据。
输入第一行包含一个整数 N(N<10000) N ( N < 10000 ) ,表示要找的零钱总额。

输出格式:

每次输出一个整数表示最少张数的纸币

SampleInput:

75
13

SampleOutput:

3
4

分析:
    找零钱问题是在我们生活中也非常常见的一个问题,例如我们拿了一张大面值的钞票(100块)去买东西,如果只是买一个2元的东西,需要找98元,那么一般售货员会先找50元面值的钞票,再找20元面值的钞票,再找10元、5元等面值的钞票使得找的钞票的张数最少。因此有了这样的思路,为了使得张数最少,只需要尽量用面额大的钞票即可。
    具体算法实现如下:

需要找N的零钱,每次取出小于N且面额最大的零钱,纸币张数加1,然后N赋值为剩下要找的零钱,以此类推直到N = 0

完整实现代码如下:

#include <iostream>
using namespace std;
int main() {
    std::ios::sync_with_stdio(false);
    int money[6] = {100, 50, 20, 10, 5, 1};
    int n;
    while (cin >> n) {
        int sum = 0;
        for (int i = 0; i < 6;i++) {
            if (n >= money[i]) {
                sum += n / money[i];
                n = n % money[i];
            }
        }
        cout << sum << endl;
    }
    return 0;
}

关于找零钱还有一个值得注意的问题

假设纸币的面值只有三种:1、3、4。在同样的问题中,如果使用贪心策略,将是错误的。
具体:假设需要找6元的零钱,那么先拿出面额最大的一张四元,然后剩下2元只能用2张一元,于是使用了3张纸币。
然而实际上,我们只需要2张三元的纸币即可。
思考:在面额满足什么条件下才能使用本贪心策略?(这个问题涉及到后续的算法内容,等到有了相关知识基础再来解决这个问题。)


例题2(区间问题)(较难)

    有n项工作,每项工作分别在 si s i 时间开始,在 ti t i 时间结束。对于每项工作,你都可以选择参加与否,如果选择了参与,那么自始至终都必须参加全程参与。此外,参与工作的时间段不能有重叠(即使是开始的时间和结束的时间重叠都不行)。

——出自《挑战程序设计竞赛》P40

你的目标是参与尽可能多的工作,那么最多能参与多少项工作呢?
例如:
区间问题
限制条件:

  • 1N10000 1 ≤ N ≤ 10000
  • 1siti109 1 ≤ s i ≤ t i ≤ 10 9

SampleInput:

5 (n的值)
1 2 4 6 8 (s的值)
3 5 7 9 10 (t的值)
(对应上图)

SampleOutput:

3 (选取工作1、3、5)

(尚未截稿)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值