【刷题之路】零钱凑整问题

有数组penny,penny中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim(小于等于1000)代表要找的钱数,求换钱有多少种方法。

经典的动态规划问题,首先需要确定状态,然后叠加即可。

首先确定初始状态,当目标钱数为0时,无论如何只有一种方法,即不用任何面值的钱

当目标钱数小于面额最小的钱时,方法数为零

定义一个二维数组,i为所使用的面额index, j为目标钱数,我们需要按行来填满这个数组,数组的最后一个元素即为所求。

假设penny中共有,1,2,5三种面额钱数,需要凑齐100块

res[0][0]  即为使用1块钱,来凑齐0元,则只有一种方法,res[0][0]=1,res[0][1]同理也等于一,直到100,

res[1][0] 即为使用2块钱来凑0元,则只有一种方法,不难看出,res[i][0]=1。这样。我们就定义好了初始状态,第一行全为1,第一列全为1

当求res[2][6]时,很显然包括两部分,首先,不使用当前的面额,只使用上一种面额,则为res[1][6],第二部分,当需要求使用当前面额时,问题就变成了用一张5块以及若干1块2块来达到目标金额的方法也就是res[2][1]所以res[2][6]=res[1][6]+res[2][1]

总结上述规则可知,res[i][j]也就等于res[i-1][j]+res[i][j-penny[i]](此处需要说明一下为什么只减去1次当前面额:有人会疑问如果我想用两张当前面额呢?其实减去当前面额后,如果目标值仍大于当前面额,则所加上的res[i][j-penny[i]]在计算的时候,一定是res[i-1][j-penny[i]]+res[i][j-penny[i]-penny[i]]计算出来的,也就是说之前的已经包含了使用一张当前面额的情况,加上本次又一次使用当前面额,即使用两张当前面额的情况,实际上已经算过了)

这样得到了递推公式,程序如下

class Exchange {
public:
    int countWays(vector<int> penny, int n, int aim) {
        // write code here
        vector<int> sub(aim+1);
        vector<vector<int>> res(n,sub);
        int i,j;
        for(i=0;i<=aim;i++){
            if(i%penny[0]==0) res[0][i]=1;
        }
        for(i=1;i<n;i++){
            res[i][0]=1;
            for(j=1;j<=aim;j++){
                if(j-penny[i]>=0) res[i][j]=res[i-1][j]+res[i][j-penny[i]]; //注意此处需要判断,如果减去小于0的话,显然不能用当前面额的纸币
                else res[i][j]=res[i-1][j];
            }
        }
        return res[n-1][aim];
        
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值