当前位置: 首页 > ops >正文

算法分析与设计实验:找零钱问题的贪心算法与动态规划解决方案

在计算机科学中,贪心算法和动态规划是两种常用的算法设计策略。本文将通过一个经典的找零钱问题,详细讲解这两种算法的实现和应用。我们将会提供完整的C++代码,并对代码进行详细解释,帮助读者更好地理解和掌握这两种算法。

问题描述

找零钱问题是这样一个问题:给定不同面值的零钱和一个总金额,如何使用最少数量的零钱来凑出这个总金额。例如,假设我们有面值为1、5、14、18的零钱,需要凑出28元,那么可能的解包括:28=18+5+5 或 28=14+14。

输入输出格式

输入:

  • 第一行:两个整数,分别表示零钱的种类数和需要凑的总金额。

  • 第二行:若干个整数,表示每种零钱的面值。

输出:

  • 分别输出贪心算法和动态规划算法得到的找零方案。

算法分析

贪心算法

贪心算法的核心思想是在每一步选择中都采取当前状态下最优的选择,从而希望导致最终结果最优。在找零钱问题中,贪心算法的策略是每次选择面值最大的零钱,尽可能多地使用这种零钱,直到无法再使用为止,然后继续选择次大的零钱,依此类推。

动态规划算法

动态规划算法通过把原问题分解为多个子问题来求解。对于找零钱问题,我们可以定义一个数组dp,其中dp[i]表示凑出金额i所需的最少零钱数量。通过填充电动态规划表,我们可以得到凑出总金额的最少零钱数,并通过回溯得到具体的找零方案。

代码实现

以下是使用C++实现的找零钱问题解决方案:

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>using namespace std;vector<int> greedyCoinChange(int Y, vector<int> coins) {sort(coins.rbegin(), coins.rend()); // 降序排列vector<int> result;int remaining = Y;for (int coin : coins) {while (remaining >= coin) {result.push_back(coin);remaining -= coin;if (remaining == 0) break;}if (remaining == 0) break;}return result;
}vector<int> dpCoinChange(int Y, vector<int>& coins) {vector<int> dp(Y + 1, INT_MAX); vector<int> coinUsed(Y + 1, 0); dp[0] = 0;for (int i = 1; i <= Y; ++i) {for (int coin : coins) {if (coin <= i && dp[i - coin] != INT_MAX && dp[i - coin] + 1 < dp[i]) {dp[i] = dp[i - coin] + 1;coinUsed[i] = coin;}}}vector<int> result;int current = Y;while (current > 0) {int coin = coinUsed[current];result.push_back(coin);current -= coin;}// 动态规划结果按降序排列sort(result.rbegin(), result.rend());return result;
}int main() {int n, Y;cin >> n >> Y;vector<int> coins(n);for (int i = 0; i < n; ++i) {cin >> coins[i];}// 贪心算法直接处理降序vector<int> greedyResult = greedyCoinChange(Y, coins);// 动态规划处理后排序vector<int> dpResult = dpCoinChange(Y, coins);// 格式化输出cout << Y << "=";for (size_t i = 0; i < greedyResult.size(); ++i) {if (i != 0) cout << "+";cout << greedyResult[i];}cout << endl;cout << Y << "=";for (size_t i = 0; i < dpResult.size(); ++i) {if (i != 0) cout << "+";cout << dpResult[i];}cout << endl;return 0;
}

代码解析

贪心算法函数 greedyCoinChange

  1. 将零钱面值按降序排列,这样可以优先使用面值较大的零钱。

  2. 初始化一个空向量 result 来存储找零方案。

  3. 使用一个循环遍历每种面值的零钱,尽可能多地使用当前面值的零钱。

  4. 当剩余金额为零时,结束循环并返回找零方案。

动态规划函数 dpCoinChange

  1. 初始化一个动态规划数组 dp,其中 dp[i] 表示凑出金额 i 所需的最少零钱数量。

  2. 初始化一个数组 coinUsed 来记录凑出每个金额时使用的最后一个零钱面值。

  3. 使用嵌套循环填充电动态规划表,外层循环遍历金额,内层循环遍历零钱面值。

  4. 通过回溯 coinUsed 数组构造找零方案。

示例输入与输出

输入

4 28
1 5 14 18

输出

28=18+5+5
28=14+14

总结

本文通过一个具体的找零钱问题,详细介绍了贪心算法和动态规划算法的实现过程。贪心算法简单直观,但在某些情况下可能无法得到最优解。而动态规划算法虽然时间复杂度较高,但可以保证得到最优解。在实际应用中,我们可以根据问题的具体特点选择合适的算法。希望本文能够帮助读者更好地理解和掌握这两种重要的算法设计策略。

http://www.xdnf.cn/news/7808.html

相关文章:

  • Nginx网站服务
  • AI+MCP 自动发布小红书笔记
  • 【基础】Windows开发设置入门9:WSL 2 上的 Docker 容器
  • 基于Go语言的恶意软件通过Redis配置滥用向Linux主机部署XMRig挖矿程序
  • [论文精读]Ward: Provable RAG Dataset Inference via LLM Watermarks
  • 数据库健康监测器(BHM)实战:如何通过 HTML 报告识别潜在问题
  • Android OkHttp控制链:深入理解网络请求的流程管理
  • 动手学习深度学习V1.1 chapter2 (2.1-2.2)
  • 读一本书第一遍是快读还是细读?
  • 物理机做完bond后network服务重启失败
  • IntelliJ IDEA 接入 DeepSeek帮助你更好编码
  • net Core》》包与库 LibMan、NPM
  • 从加密到信任|密码重塑车路云一体化安全生态
  • 【Redis】二、Redis常用数据类型命令学习
  • 电感在断开的时候会按原来的电流方向流动这是什么定理?
  • Baklib内容中台的构建要点是什么?
  • 【性能测试】jvm监控
  • 前端JavaScript学习-动态编码-基础
  • 【每周一个MCP】:将pytdx封装成MCP
  • NFM算法解析:如何用神经网络增强因子分解机的特征交互能力?
  • 基于Qt的app开发第十天
  • 每日leetcode
  • opencv的图像卷积
  • 物联网相关词汇
  • Pandas:数据分析步骤、分组函数groupby和基础画图
  • matlab二维随机海面模拟
  • C++之模板进阶(探索C++模板:非类型参数与特化技巧)
  • Linux网络 网络基础一
  • 山东大学高级程序设计期末复习
  • BERT、GPT-3与超越:NLP模型演进全解析