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

来源:互联网 发布:简述网络整合营销理论 编辑:程序博客网 时间:2024/05/16 15:05

有数组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];
        
    }
};

0 0
原创粉丝点击