贪婪算法是一种在每一步选择中都采取当前状态下最优决策的策略,以期望通过一系列局部最优选择达到全局最优。贪婪算法通常适用于优化问题,其中需要在有限时间内做出一系列决策,每个决策都是基于当前状态的最优选择。
基本原理和步骤
-
问题建模: 将问题抽象成一个数学模型,定义问题的目标函数以及每一步的选择。
-
贪心选择: 在每一步中,做出当前状态下的最优选择,即选择能够在局部最优条件下达到全局最优的方案。
-
问题约减: 将原问题约减为一个规模更小的子问题,以便通过贪婪选择求解。
-
循环迭代: 重复步骤 2 和步骤 3,直到达到问题的终止条件。
核心思想
贪婪算法的核心思想是每一步都选择当前状态下的最优解,而不考虑过去的选择或未来的影响。它相信通过每次选择局部最优解,最终可以达到全局最优。然而,这并不总是成立,因此贪婪算法并不适用于所有问题。
贪婪算法的优点在于简单、高效,通常具有较低的计算复杂度。它适用于那些无后效性的问题,即当前的选择不会影响以后的决策。但需要注意的是,贪婪算法并不保证一定能够找到全局最优解,有些情况下可能只能得到局部最优解。
示例:找零钱问题
让我们以找零钱问题为例,说明贪婪算法的应用:
问题描述: 给定一定面额的硬币,要求找零钱的最少硬币数量。
贪婪算法解决:
-
问题建模: 定义问题的目标函数是找零钱所需的最少硬币数量。
-
贪心选择: 在每一步中,选择面额最大的硬币,直到找零完成。
-
问题约减: 将原问题约减为一个规模更小的子问题,即找零剩余的金额。
-
循环迭代: 重复步骤 2 和步骤 3,直到找零完成。
#include <iostream>
#include<vector>
#include<algorithm>
std::vector<int>makeChange(int amount, const std::vector<int>& coins)
{
std::vector<int>change; //存储找零的硬币
//降序排列面值,以便在贪婪算法选择面值最大的硬币
std::vector<int> sortedCoins(coins);
std::sort(sortedCoins.rbegin(),sortedCoins.rend()); //降序排列
for (const int coin : sortedCoins)
{
//反复选择面值最大的硬币,直到找零完成
while (amount >= coin)
{
amount -= coin; //找零金额减去当前硬币的面值
change.push_back(coin); //将当前硬币加入找零的硬币中
}
}
return change;
}
int main()
{
int amount = 93; //需要找零的金额
std::vector<int> coins = { 1,5,10,20,50 }; //可用的硬币面值
std::vector<int> change = makeChange(amount, coins);
std::cout<<"需要找零的金额为:"<<amount<<std::endl;
std::cout<<"找零需要的硬币为:";
for (int coin : change)
{
std::cout<<coin<<" ";
}
std::cout << std::endl;
}
运行结果