硬币找零

备注:可以参考背包问题的求解方式

一、问题描述:

有n种不同币值的硬币x1,x2,…,xn,各种硬币的可使用数量无上限,给定币值s,若存在由该n中硬币组成的找零方案则求所需最少硬币数量,否则返回-1。

二、问题分析:

动态规划求解。设f(i, j)表示利用前i种硬币获得币值j时所需的最少硬币数,则f(n, s)即为利用前n种硬币获得币值s时所需的最少硬币数。用前0种硬币获得币值0所需最少硬币数量为0,用前0中硬币不可能获得币值j(j>0),为方便计算设其为一个很大的数MAX_N。故有如下目标函数:

f(0, 0)=0;

f(0, j)=MAX_N, 1<=j<=s;

f(i, j)=min{f(i-1, j), min{f(i-1, j-k*xi)+k | 0<k*xi<=j,且f(i-1, j-k*xi)!=MAX_N}}, 1<=i<=n, 0<=j<=s;

上述分析中,时间复杂度为O(n*s*(s/min{xi})),空间复杂度O(n*s)。有f(i, j)求解过程可知f(i, j)只与f(i-1, t), 0<=t<=j有关,故只需保存f(i-1, t),而计算f(i-1, j-k*xi)+k-1实际上是在求解f(i, j-k*xi),故时间复杂度可以改进为O(n*s),空间复杂度可以改进为O(s)。

三、代码实现:

算法实现:

int min_num(int * arr,int size,int s){
	assert(arr!=NULL);
	const int MAX_N=0x7FFFFFFF;
	int *min=new int[s+1];
	if(min==NULL){
		exit(0);
	}
	min[0]=0;
	for(int i=1;i<=s;++i){
		min[i]=MAX_N;
	}
	for(int i=0;i<size;++i){
		for(int j=arr[i];j<=s;++j){
			if(min[j-arr[i]]!=MAX_N&&min[j-arr[i]]+1<min[j]){
				min[j]=min[j-arr[i]]+1;
			}
		}
	}
	if(min[s]!=MAX_N){
		return min[s];
	}else{
		return -1;
	}
}

测试代码:

#include<cstdlib>
#include<cassert>
#include<iostream>

int min_num(int * arr,int size,int s);
using namespace std;

int main(int argc,char*argv[]){
	int arr[]={3,5,7,8,10,11,13,17,19,23,29};
	int s;
	int size=sizeof arr/sizeof(int);
	cout<<size<<endl;
	cin>>s;
	cout<<min_num(arr,size,s);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值