硬币组合


title: 硬币组合
date: 2018-4-5 10:12:40
categories:
- algorithm
tags:

- algorithm

问题

给定一个数值sum,假设我们有m种不同类型的硬币{V1, V2, …, Vm},如果要组合成sum,求所有可能的组合数。
给定一个数值sum,假设我们有m种不同类型的硬币{V1, V2, …, Vm},如果要组合成sum
sum = x1*v1 + x2*v2 + x3*v3 + ..... + xm*vm
求所有可能的组合数,求满足所有等值的系数{x1,x2,x3,...xm}

暴力破解

枚举,每个系数取值
x1 = {0,1,2….sum/v1}
x2 = {0,1,2….sum/v2}
.
.
.
.

复杂度很高

动态规划

设vm硬币取值 0-m  
sum = x1*v1 + x2*v2 + x3*v3 + .... + 0*vm
sum = x1*v1 + x2*v2 + x3*v3 + .... + 1*vm
sum = x1*v1 + x2*v2 + x3*v3 + .... + 2*vm
sum = x1*v1 + x2*v2 + x3*v3 + .... + 3*vm
               .......
sum = x1*v1 + x2*v2 + x3*v3 + .... + k*vm

k = sum/vm
dp[i][sum] = 前i种硬币构成sum的所有组合数
dp[i][sum] =
dp[i-1][sum - 0*Vm] + dp[i-1][sum - 1*Vm]+ dp[i-1][sum - 2*Vm] + … + dp[i-1][sum - K*Vm]; 其中K = sum / Vm

数学表达

一般例子解答:
假设我们有3种不同面值的硬币{1,2,5},用这些硬币组合够成一个给定的数值n。
问总过有多少种可能的组合方式?保证n小于等于100000。

public static void main(String[] args) {
    for (int i = 1; i < 10; i++) {
        System.out.println(coin_count(i));
    }
}
public static int coin_count (int n) {
    int[] coins = {1,2,5};
    int[] dp = new int[100000];
    dp[0] = 1;
    for (int i = 0; i < coins.length; i++) {
        for (int j = coins[i]; j <= n; j++) {
            dp[j] = dp[j] + dp[j - coins[i]];
        }
    }
    return dp[n];
}

结果:
1
2
2
3
4
5
6
7
8


硬币问题的变幻

现在给定入肝硬币, 例如{1,2,5},sum = 11 result = 3; 11 = 5+5+1 求组合成sum的最少的硬币数,如果无法组合,例如 {2}, sum = 3 ; result = -1.

dp[0] = 0;
dp[1] = 1;
dp[2] = min(dp[2], dp[2 - 1] + 1, dp[2 - 2] + 1) = dp[0] + 1 = 1; 
dp[3] = min(dp[3], dp[3 - 1] + 1, dp[3 - 2] + 1) = dp[1] + 1 = 2;
........
dp[n] = min(dp[n], dp[n - coins[j]] + 1) : coins[j] <= n;
public static int coinChange(int[] coins, int amount) {
    if (coins == null || coins.length == 0 || amount <= 0) {
        return 0;
    }
    if (coins.length == 1) {

    }
    int[] dp = new int[amount + 1];
    Arrays.fill(dp, 100000);
    dp[0] = 0;
    for (int i = 1; i <= amount; i++) {
        for (int j = 0; j < coins.length; j++) {
            if (i >= coins[j]) {
                dp[i] = Math.min(dp[i], dp[i - coins[j]]+ 1);
            }
        }
    }
    return dp[amount] == 100000?-1:dp[amount];
}

猜你喜欢

转载自blog.csdn.net/qq_33797928/article/details/79896895
今日推荐