动态规划应用--找零钱
文章目录
- 1. 问题描述
- 2. 问题分析
- 2.1 回溯法求解
- 2.2 DP状态转移方程法
- 2.3 DP状态转移表法
1. 问题描述
找零问题,在贪心算法讲过。但是贪心不一定能得出最优解。假设有几种不同币值的硬币v1,v2,.……vn(单位是元)。如果要支付w元,求最少需要多少个硬币。比如,有3种不同的硬币,1元、3元、5元,我们要支付9元,最少需要3个硬币(3个3元的硬币)。
2. 问题分析
2.1 回溯法求解
/*** @description: 找零钱,需要张数最少,回溯法* @author: michael ming* @date: 2019/7/20 22:50* @modified by:*/
#include <iostream>
#define N 3
int rmb[N] = {1,9,10};//钞票面额
int amount[N];
int minAmount[N];
using namespace std;
void exchange(const int &targetMoney, int curMoney, int &minPiece, int piece)
{if(curMoney > targetMoney)//超过目标,返回return;if(curMoney == targetMoney)//达到目标金额{if(piece < minPiece){minPiece = piece;//更新最小张数for(int i = 0; i < N; ++i)minAmount[i] = amount[i];//获取每张钞票的张数}return;}for(int i = 0; i < N; ++i){//递归调用,拿取每张面额的钞票amount[i]++;exchange(targetMoney,curMoney+rmb[i],minPiece,piece+1);amount[i]--;//恢复上次的状态}
}
int main()
{int minPiece = 65535, piece = 0,targetMoney = 18, curMoney = 0;exchange(targetMoney,curMoney,minPiece,piece);cout << "凑成" << targetMoney << "元,最少需要:" << minPiece << "张(枚)。" << endl;int i = 0;while(i < N){if(minAmount[i] != 0)cout << minAmount[i] << "个" << rmb[i] << " ";i++;}cout << endl;cout << "----------------------" << endl;
}
2.2 DP状态转移方程法
由于上面的钞票面额可能不止3种,递归树是多叉树,所以状态转移表法画起回溯的递归图比较麻烦,我们采用状态转移方程法。
状态转移方程如下:
minPiece(targetMoney) = 1 + min{minPiece(targetMoney-rmb[0]), ... , minPiece(targetMoney-rmb[N-1])}
targetMoney = 18;//目标金额
rmb[N] = {1,9,10};//钞票面额
对于题目的情况,代入具体数值,状态转移方程如下
minPiece(18) = 1 + min{minPiece(18-1), minPiece(18-9) , minPiece(18-10)}= 1 + min{minPiece(17),minPiece(9),minPiece(8)}
DP(递归+备忘录)代码如下:
/*** @description: 找零钱,需要张数最少* @author: michael ming* @date: 2019/7/20 18:35* @modified by: */
#include <iostream>
#include <algorithm>
#include <memory.h>#define N 3
const int targetMoney = 18;//目标金额
int rmb[N] = {1,9,10};//钞票面额
int mem[targetMoney+1];//备忘录,存放最小张数
using namespace std;
int minP(int Money)
{if(Money < 0)//超过目标,返回很大的张数,表示不可能凑成return 65535;if(Money == 0)//达到目标金额return 0;if(mem[Money] > 0)//计算过了,直接读取备忘录return mem[Money];int minAmount[N];memset(minAmount,65535,N*sizeof(int));for(int i = 0; i < N; ++i){//递归调用,拿取每张面额的钞票minAmount[i] = minP(Money-rmb[i]);}sort(minAmount,minAmount+N);mem[Money] = minAmount[0]+1;//记录最小的张数return mem[Money];
}
int main()
{cout << "凑成" << targetMoney << "元,最少需要:"<< minP(targetMoney) << "张(枚)。" << endl;//如何打印出选取钞票的面额和张数???
}
2.3 DP状态转移表法
/*** @description: 找零钱,需要张数最少,dp状态表法* @author: michael ming* @date: 2019/7/21 20:01* @modified by: */
#include <iostream>
#include <algorithm>
#include <memory.h>#define N 3
const int targetMoney = 18;//目标金额
int rmb[N] = {1,9,10};//钞票面额,从小到大
using namespace std;
void exchange(int Money)
{int maxPiece = targetMoney/rmb[0];//最大张数int i, j, k;int (*states)[targetMoney+1] = new int [maxPiece][targetMoney+1];//memset(states,65535,maxPiece*(targetMoney+1)*sizeof(int));//上面错误!!!memset一般只付0或极大值for(i = 0; i < maxPiece; ++i)for(j = 0; j <= targetMoney; ++j)states[i][j] = 65535;//初始化for(k = 0, j = 0; j <= targetMoney; ++j){if(k < N && j == rmb[k]){//初始化第一行数据states[0][j] = 1;//一张rmbk++;}}for(i = 1; i < maxPiece; ++i)//动态规划{for(j = 0; j <= targetMoney; ++j)//上面一行的数据考下来states[i][j] = states[i-1][j];for(j = 0; j <= targetMoney; ++j){if(states[i-1][j] != 65535){for(k = 0; k < N; ++k){if(j+rmb[k] <= targetMoney && states[i-1][j+rmb[k]] > states[i-1][j]+1)states[i][j+rmb[k]] = states[i-1][j]+1;}}}}cout << "凑成" << targetMoney << "元,最少需要:"<< states[maxPiece-1][targetMoney] << "张(枚)。" << endl;//------------打印选择的信息---------------------------for(i = maxPiece-1; i >= 1 && states[i][targetMoney] == states[i-1][targetMoney]; --i);//此时i等于最早出现的答案处的行for(j = targetMoney; j > 0; ){if(i != 0){for(k = 0; k < N; ++k){if(states[i-1][j-rmb[k]] == states[i][j]-1){cout << "1张" << rmb[k] << " ";j = j-rmb[k];i--;break;}}}else{cout << "1张" << j << " ";break;}}delete [] states;//释放资源
}
int main()
{exchange(targetMoney);return 0;
}
动态规划应用--找零钱相关推荐
- 【README3】动态规划之“找零钱”说明最优子结构怎么解决
接上文:[README2]动态规划之斐波那契数列说明重叠子问题如何解决 文章目录 找零钱问题说明最优子结构 (1)何为最优子结构 (2)状态转移方程 暴力解法 (3)备忘录解决重叠子问题 (4)迭代解 ...
- 【恋上数据结构】动态规划(找零钱、最大连续子序列和、最长上升子序列、最长公共子序列、最长公共子串、0-1背包)
动态规划(Dynamic Programming) 练习1:找零钱 找零钱 - 暴力递归 找零钱 - 记忆化搜索 找零钱 - 递推 思考题:输出找零钱的具体方案(具体是用了哪些面值的硬币) 找零钱 - ...
- java 动态规划找零钱_动态规划之找零钱问题
找零钱是一个经典的动态规划问题.这种问题,我建议,首先学会暴力解法,然后从暴力解法中优化出动态规划的解法,这样,更能体会动态规划的魅力. 问题描述 有n种不同币值的硬币,硬币数量无限.给定一个数量T, ...
- java 动态规划找零钱_初探动态规划——LeetCode找零钱问题
1.简介: 在leetcode上刷题的时候,遇到了一道找零钱的动态规划题,后台测试用例很变态,必须把算法优化的很好才能通过.也借此机会好好的研究了一下动态规划.在下小白一个,大神轻喷. 2.题目如下: ...
- 动态规划解决找零钱问题
动态规划算法 通常用于求解具有某种最优性质的问题.动态规划算法与分治法类似,其基本思想都是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解.与分治法不同的是,适合于用动 ...
- $动态规划系列(2)——找零钱问题
refer:http://interactivepython.org/courselib/static/pythonds/index.html 1. 问题描述 Tom在自动售货机上买了一瓶饮料,售价3 ...
- 【数据结构】动态规划——找零钱问题解析(含c++和python代码)
一个具体的找零钱问题: 参考:程序员面试再也不怕动态规划了,看动画,学DP,找零钱 (LeetCode 322) 硬币面值:1,2,5,7,10 找零金额:14 step1:定义长度为15的dp数组 ...
- 动态规划算法思想解决找零钱问题
前言 关于找零钱问题,网上已经有很多相关的资料以及优秀的文章博客等.这里写这篇博客的初衷很简单,就是为了方便自己,回过头来捡起这个知识能快一点,接受起来更易理解点:他人的文章写的再好,毕竟是别人的,学 ...
- 动态规划--找零钱有多少种方法
问题: 给定数组arr,arr中的所有的值都为正数且不重复.每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求换钱有多少种方法. 分析:arr长度为N,生成 ...
最新文章
- 19岁大学生网恋被骗318万!见到“女神”后傻了,对方竟有200斤!
- R使用深度学习LSTM构建时间序列预测模型
- 成功解决xgboost.core.XGBoostError: b'[20:58:45] C:\\Users\\Administrator\\Desktop\\xgboost\\dmlc-core\\s
- MongoDB基本概念和安装配置
- 吞噬星空怎么会有鸿蒙,论吞噬星空与鸿蒙的关系
- linux centos7 cuda安装
- Linux 系统编程技巧与概念 第12章 基于 TLV 传输
- CUDA Study Notes
- 雷锋科普:小米M2之芯高通APQ8064芯片组解析
- google,翻译英文网站
- 《计算机科学与工程导论:基于IoT和机器人的可视化编程实践方法第2版》一2.1 工作流和可视化编程...
- 【SpringCloud 2021.0.0】12、路由网关Gateway之简介 (spring-boot 2.6.3)
- 设计模式之浅浅的理解桥接模式
- MySQL Replication 梳理详解
- 打印ASCII码 c++
- python判定固定时长固定频率的音频是否连续
- sio.savemat得到空struct解决方法
- 养生需知:藏在水里的“杀机” 你遇到了吗
- 一篇搞定css基础(超详细,附代码)
- 【日本雅虎新闻推荐】:Embedding-based News Recommendation for Millions of Users(附开源代码)