美团笔试题(一)-[编程题] 拼凑钱币

[编程题] 拼凑钱币

给你六种面额 1、5、10、20、50、100 元的纸币,假设每种币值的数量都足够多,编写程序求组成N元(N为0~10000的非负整数)的不同组合的个数。

输入描述:

输入包括一个整数n(1 ≤ n ≤ 10000)

输出描述:

输出一个整数,表示不同的组合方案数

输入例子1:

1

输出例子1:

1

分析:其中假设所有的钱币总数为 V = V 0 , V 1 , V 2 , , V i 。总共有 i 种钱币。我们用 d p [ i ] [ n ] 表示用 i 种钱币表示组成 n 元的组合数。我们依次分析12元以内的硬币组合数量。

当我们只使用1种硬币的时候,所有的组合情况如下:

使用硬币数 1 2 3 4 5 6 7 8 9 10 11
只使用1 1 1 1 1 1 1 1 1 1 1 1
1和5 1 1 1 1 2 2 2 2 2 3 3
1、5和10 1 1 1 1 2 2 2 2 2 4 4

依次往下。

当我们增加一种硬币(硬币5)的时候,组合的结果相对于只使用1来说是,在原有只有1的统计基础上行,增加 1 个5元硬币输出的组合情况 + 增加2个5元硬币输出得组合情况 + … + 直到增加到最大的 5 元硬币数量为止。就如具体的取 n = 10 来说明。

当我们新增加一个5元硬币时,使用硬币5的所有次数取值范围为 0 , 1 , 2 。其中 2 = m a x [ n 5 ]

我们分情况来考虑:

  1. 当使用0个5元时,就是上面用1组成数字n的情况;
  2. 当时用1个5元时,就是上面用1组成数字n-5的情况;
  3. 当使用2个5元时,就是上面用1组成数字n-2*5的情况。

所以,当使用1和5两种硬币表示数字n=10的时候,就是讲上面的所有情况累加 d p [ 2 ] [ 10 ] = d p [ 1 ] [ 10 ] + d p [ 1 ] [ 5 ] + d p [ 1 ] [ 0 ] 。总结成通用的公式就如下所示

d p [ i + 1 ] [ n ] = i = 0 k d p [ i ] [ n i × v i + 1 ] k = 0 , 1 , , m a x [ n / v i + 1 ]

代码实现如下:

public class Solution {
    static int[] values = {1,5,10,20,50,100};
    static int combine(int n) {
        n++; // 主要是需要多增加一个为0的时候空位,不然会出错
        int[][] dp = new int[values.length][n];
        for (int i = 0; i < n; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i < values.length; i++) {
            for (int j = 0,k; j < n; j++) {
                k = j/values[i];
                while(k>=0){
                    dp[i][j] += dp[i-1][j-k*values[i]];
                    k--;
                }
                System.out.print(dp[i][j]+"\t");
            }
            System.out.println();
        }
        return dp[values.length-1][n-1];
    }
    public static void main(String[] args){
        System.out.println(combine(20));
    }
}

猜你喜欢

转载自blog.csdn.net/u013019701/article/details/81262013