您的位置:首页 > 其它

最少找零问题与完全背包模型的一点思考

2015-10-01 16:18 405 查看
最少找零问题描述如下,有n张硬币,价值存储在一个数组中,每种硬币个数都是无限的,再给定一个要找的零钱数,然后试用最少的数目的硬币来找我们要求的数目。比如  5,2,3,要找出20元钱,我们人工的判断几个可能,很快就可以找出最优,也就是4张5元,也就是4.如果这个题目要求用程序解决,我们可以遵循如下思路首先如果全部用5元,则其最多4张,如果全部用2元,则最多是10张,如果全部3元,最多6张(如果是7张,则大于20元),所以我们可以使用暴力递归来判断,在0张5元,0张2元,0张3元, 或者0张5元,0张2元,1张3元,或者0张5元,0张2元,2张3元·······以钱币金额为标准,其调用的数目表格如下,5    2   3——————0     0    00     0    10     0    20     0    30    0     40    0      50     0     60    1     00    1     10    1     20     1     30      1    40     1    50     1    60     2    00    2      10    2     20     2     30     2     40     2     5      (这里3元金额的数目为5,而没有到6,是因为前面调用了0张5元,2张2元,这是剩余金额为20-2*2=16元,最多需要5张)0     3     0··············从以上表格可以看到在标注的地方,选择了0张5元,2张2元,5张3元,这时候还剩1元,这个需要我们考虑,如果多了1元,该如何处理。如果做过背包问题的多重背包问题,必然知道这个题目的模型和多重背包是很类似的,一个深度搜索,在下标到达边界时候,返回一个值,但是多重背包返回的是0,而且多重背包完全不会考虑你装完最后一个物品后, 你的背包容量还剩几个单元,是正好装满,还是差几个单元,它只关注他的总体最大价值,而这个题和完全背包问题的区别在于,这个题需要判断,我们在递归到边界的时候,“背包”的容量还有多少,如果前面选择了x个5元,y个2元,z个3元,这时候再递归到边界时候,“背包”剩余容量是0,代表前面的这些组合正好组成了我们需要的金钱数目,这时候需要返回什么?同样如果前面选择了x个5元,y个2元,z个3元,这时候再递归到边界时候,“背包”剩余容量不是0,代表前面的组合没有组成我们要的数目,还差几块钱,这时候,要返回什么?很明显,面对第一个问题,我们只需要返回0就可以了,然后前面的硬币数目(比如 x y z)加上返回值,就可以返回其组合数。面对第二个问题,我们可以用一个例子来看看5   2     3——————···········0   4     0 ----->  要给前面返回一个比较大的值0   4     1 ----->  要给前面返回一个比较大的值0   4     2 ----->  要给前面返回一个比较大的值0   4     3 ----->  要给前面返回一个比较大的值0   4    40   5    00   5    10   5    2上面是几组数据, 对于前四组,我们口算就可以得知其都不可以组合成20,递归到边界时候,要返回一个值,返回谁?如果是0,肯定是错误的,我们可以返回一个比较大的值,比如#define MAXSIZE 10010,返回这个MAXSIZE,往下走,在0   4   4 时候,正好可以组合成20元,返回0,然后0+4+4+0(相加顺序是从后往前的,因为递归本来就是从后往前回溯的)=8,对于0张5元,4张2元,我们可以得到5个返回值,分别是 MAXSIZE, MAXSIZE, MAXSIZE, MAXSIZE,8,我们找到这里面最小的8,就可以结束(0,4,x)这个递归了,后面也都是一样。总结下,如果递归到边界时候,剩余硬币数目为0,也就是刚刚好,要返回0,如果是非0,则返回一个预定义的一个较大值,代码如下。
#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>using namespace std;#define MAXSIZE 10010int arr[100]={3,5};int fun(int arr[],int index,int aim){int ret=MAXSIZE;if(index==2){if(aim==0)return 0;elsereturn MAXSIZE;}if(aim<=0){return 0;}for(int i=0;i*arr[index]<=aim;i++){ret=std::min(ret,i+fun(arr,index+1,aim-i*arr[index]));}return ret;}int main(){if(MAXSIZE==fun(arr,0,2)){cout<<0<<endl;}elsecout<<fun(arr,0,22);return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: