【程序设计竞赛算法】贪心法——硬币问题
硬币问题是一个经典的贪心算法应用场景,即找零问题(Coin Change Problem)。给定一组不同面额的硬币和一个要找零的金额,要求找出最少需要的硬币数量来凑成该金额。
下面介绍一种常见的贪心算法解决硬币问题的思路,称为"贪心选择+贪心定理"。
假设有一组硬币面额 coins = [c1, c2, …, ck],要找零的金额为 amount。我们需要找到最少的硬币数量,使得这些硬币的面额总和等于 amount。
1、首先,对硬币面额进行降序排序,保证每次选择的硬币面额都是最大的。
2、初始化一个变量 count,用于记录硬币的数量。
3、从面额最大的硬币开始,逐个尝试将该硬币加入找零集合中,直到达到目标金额 amount 或无法再添加硬币为止。
**·**如果当前硬币面额 ci 小于等于目标金额 amount,那么将该硬币加入找零集合,并将目标金额减去该硬币面额。
**·**如果当前硬币面额 ci 大于目标金额 amount,则放弃该硬币,尝试下一个面额较小的硬币。
4、重复步骤3,直到目标金额 amount 为0。
5、返回硬币数量 count。
下面是一个使用贪心算法解决硬币问题的示例代码:
#include <stdio.h>
int coinChange(int coins[], int n, int amount) {
int count = 0;
for (int i = n - 1; i >= 0; i--) {
while (coins[i] <= amount) {
amount -= coins[i];
count++;
}
}
if (amount == 0) {
return count;
} else {
return -1; // 无法凑出目标金额
}
}
int main() {
int coins[] = {1, 5, 10, 25};
int amount = 36;
int n = sizeof(coins) / sizeof(coins[0]);
int minCoins = coinChange(coins, n, amount);
printf("最少需要的硬币数量:%d\n", minCoins);
return 0;
}
在上述代码中,我们定义了一个 coinChange 函数,接受硬币面额数组 coins[]、硬币数量 n 和目标金额 amount 作为参数,返回最少需要的硬币数量。
在 coinChange 函数中,我们使用贪心算法的思路。首先,我们从硬币面额数组的最大面额开始遍历,因此我们使用逆序的循环。对于每个硬币面额 coins[i],我们尽可能多地使用它,直到它不能再被凑出目标金额为止。我们不断将当前硬币面额加入找零集合中,并将目标金额减去该硬币面额。最终,我们得到最少需要的硬币数量。
最后,如果目标金额 amount 等于 0,则返回硬币数量 count;否则返回 -1,表示无法凑出目标金额。
在 main 函数中,我们给定了一组硬币面额 coins[] = {1, 5, 10, 25},要找零的金额为 36。通过调用 coinChange 函数,得到最少需要的硬币数量,并输出结果。
需要注意的是,贪心算法在某些情况下可能无法得到最优解。在硬币问题中,贪心算法可以得到最优解的前提是硬币面额之间存在倍数关系,即较大面额的硬币是较小面额硬币的倍数。对于一般的硬币面额组合,贪心算法不一定能够得到最优解,此时可以考虑使用动态规划等其他方法。