动态规划之换钱的最少货币数

这篇博客探讨了如何使用动态规划解决找零问题。给定一个包含不同面值货币的数组arr和目标金额aim,目标是找出达到aim所需的最少货币数。博主详细解析了问题,解释了动态规划表格的构建,并给出了关键的转移方程。最后,提供了C++实现代码。
摘要由CSDN通过智能技术生成

1、题目描述:给定数组arr,,大小为N,arr中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数,求组成aim的最少货币数。

举例:arr=[5,2,3],aim=20,返回4;arr=[5,2,3],aim=0,返回0;arr=[3,5],aim = 2,返回-1。

2、题目解析:

1)组合数学中的母函数一节可以很好的解决这个问题;

2)从动态规划的角度来看,首先要确定动态规划表dp,在这里dp[i][j]的含义是:使用任意的a[0]...a[i],组合成j的最小货币数,因此动态规划表的大小为N行,aim+1列。具体为什么这么构造dp表,我也不清楚,准备多做一些类似的题目看一看。

3)接下来的关键就是构造dp[i][j]的表达式了,分成使用a[i]和不使用a[i]的情况(也可以根据其他的货币来分类,不过用a[i]分类容易)。不使用a[i]的话,dp[i][j]=dp[i-1][j],也就是使用a[0]...a[i-1]就能够组合出了aim了;使用a[i]的话,dp[i][j]=dp[i][ j-arr[i] ]+1(确保j-arr[i]>=0),也就是使用任意张a[0]...a[i]组合出j-arr[i],最后加上a[i](为什么是这样,我也不清楚尴尬)。


3、最后附上代码:

/*2017-11-20
* 换钱的最少货币数:给定数组arr,arr中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim代表要找的钱数
* 求组成aim的最少货币数
*/
#include<iostream>
#include<vector>

using namespace std;
int min(int v1, int v2);
int main() {
	int N, aim;
	int max = 65536;
	cout << "please input N and aim:" << endl;
	cin >> N >> aim;//输入货币面值的种类数和目标钱数

	vector<int> arr(N);
	vector<vector<int>> dp(N, vector<int>(aim + 1));

	//输入各种面值
	cout << "please input arr:" << endl;
	for (auto it_arr = arr.begin(); it_arr != arr.end(); ++it_arr) {
		cin >> *it_arr;
	}
	dp[0][0] = 0;
	//对dp的第一行进行初始化
	for (int i = 1; i < aim + 1; ++i) {
		if (i%arr[0] == 0) {
			dp[0][i] = i / arr[0];
		}
		else {
			dp[0][i] = max;//max代表无法组成这个aim
		}
	}
	//对dp第一列进行初始化,全为0
	for (int j = 1; j < N; j++) {
		dp[j][0] = 0;
	}
	//计算dp[i][j],最终返回dp[N-1][aim]
	for (int i = 1; i < N; ++i) {
		for (int j = 1; j < aim + 1; ++j) {
			if (arr[i] > j) {
				dp[i][j] = dp[i - 1][j];
			}
			else {
				dp[i][j] = min(dp[i - 1][j], dp[i][j - arr[i]] + 1);
			}
		}
	}
	if (dp[N - 1][aim] == 65536)dp[N - 1][aim] = -1;
	//输出结果
	cout << "the minimum number is: " << dp[N - 1][aim] << endl;
}
int min(int v1, int v2) {
	if (v1 < v2) return v1;
	else return v2;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值