算法:货币数组组成面值的方法数-同值无差别(张数限定)

题目描述

arr是货币数组,其中的值都是正数。再给定一个正数aim。 每个值都认为是一张货币,认为值相同的货币没有任何不同,返回组成aim的方法数

例如:arr = {1,2,1,1,2,1,2},aim = 4
方法:1+1+1+1、1+1+2、2+2

一共就3种方法,所以返回3

题目解析

暴力递归

class Solution {
    struct Info{
        std::vector<int> coins;
        std::vector<int> zhangs;
    };

    Info getInfos(vector<int>& coins){
        std::map<int, int> mapper;
        for(auto i : coins){
            ++mapper[i];
        }

        Info info;
        for(auto i : mapper){
            info.coins.emplace_back(i.first);
            info.zhangs.emplace_back(i.second);
        }
        return info;
    }


    int process(vector<int>& coins, vector<int>& zhangs, int idx, int rest){
        int N = coins.size();
        if(idx == N){
            return rest == 0 ? 1 : 0;
        }

        int ways = 0;
        for (int zhang = 0; zhang * coins[idx] <= rest && zhang <= zhangs[idx]; ++zhang) {
            ways += process(coins, zhangs, idx + 1, rest - zhang * coins[idx]);
        }
        return ways;
    }
public:
    int coinsWay(vector<int>& coins, int amount){
        if(amount < 0){
            return -1;
        }
        if(amount == 0 || coins.empty()){
            return 0;
        }

        auto item = getInfos(coins);
        return process(item.coins, item.zhangs, 0, amount);
    }
};

暴力递归改动态规划

class Solution {
    struct Info{
        std::vector<int> coins;
        std::vector<int> zhangs;
    };

    Info getInfos(vector<int>& coins){
        std::map<int, int> mapper;
        for(auto i : coins){
            ++mapper[i];
        }

        Info info;
        for(auto i : mapper){
            info.coins.emplace_back(i.first);
            info.zhangs.emplace_back(i.second);
        }
        return info;
    }


    int process(vector<int>& coins, vector<int>& zhangs, int idx, int rest){
        int N = coins.size();
        if(idx == N){
            return rest == 0 ? 1 : 0;
        }

        int ways = 0;
        for (int zhang = 0; zhang * coins[idx] <= rest && zhang <= zhangs[idx]; ++zhang) {
            ways += process(coins, zhangs, idx + 1, rest - zhang * coins[idx]);
        }
        return ways;
    }
public:
    int coinsWay(vector<int>& moneys, int amount){
        if(amount < 0){
            return -1;
        }
        if(amount == 0 || moneys.empty()){
            return 0;
        }

        auto item = getInfos(moneys);
        auto coins = item.coins, zhangs = item.zhangs;
        int N = coins.size();
        std::vector<std::vector<int>> dp(N + 1, std::vector<int>(amount + 1, 0));
        dp[N][0] = 1;
        for (int idx = N - 1; idx >= 0; --idx) {
            for (int rest = 0; rest <= amount; ++rest) {
                int ways = 0;
                for (int zhang = 0; zhang * coins[idx] <= rest && zhang <= zhangs[idx]; ++zhang) {
                    ways += dp[idx + 1][rest - zhang * coins[idx]];
                }
                dp[idx][rest] =  ways;
            }
        }

        return dp[0][ amount];
    }
};

斜率优化

有上面可以推出:(假设只有5张)

  • d p [ 2 ] [ 20 ] = d p [ 3 ] [ 20 ] + d p [ 3 ] [ 18 ] + d p [ 3 ] [ 16 ] + d p [ 3 ] [ 14 ] + d p [ 3 ] [ 12 ] + d p [ 3 ] [ 10 ] dp[2][20] = dp[3][20] + dp[3][18] + dp[3][16] + dp[3][14] + dp[3][12] + dp[3][10] dp[2][20]=dp[3][20]+dp[3][18]+dp[3][16]+dp[3][14]+dp[3][12]+dp[3][10]
  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 ] + d p [ 3 ] [ 20 ] + d p [ 3 ] [ 18 ] + d p [ 3 ] [ 16 ] + d p [ 3 ] [ 14 ] + d p [ 3 ] [ 12 ] dp[2][22] = dp[3][22] + dp[3][20] + dp[3][18] + dp[3][16] + dp[3][14] + dp[3][12] dp[2][22]=dp[3][22]+dp[3][20]+dp[3][18]+dp[3][16]+dp[3][14]+dp[3][12]

因此:

  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 ] + d p [ 2 ] [ 20 ] − d p [ 3 ] [ 10 ] dp[2][22] = dp[3][22] + dp[2][20] - dp[3][10] dp[2][22]=dp[3][22]+dp[2][20]dp[3][10]

又因为:

  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − 0 ∗ 2 ] + d p [ 3 ] [ 22 − 1 ∗ 2 ] + d p [ 3 ] [ 22 − 2 ∗ 2 ] + d p [ 3 ] [ 22 − 3 ∗ 2 ] + d p [ 3 ] [ 22 − 4 ∗ 2 ] + d p [ 3 ] [ 22 − 5 ∗ 2 ] dp[2][22] = dp[3][22 - 0 * 2] + dp[3][22 - 1 * 2] + dp[3][22 - 2 * 2] + dp[3][22 - 3* 2] + dp[3][22 - 4 * 2] + dp[3][22 - 5 * 2] dp[2][22]=dp[3][2202]+dp[3][2212]+dp[3][2222]+dp[3][2232]+dp[3][2242]+dp[3][2252]
  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − 0 ∗ 2 ] + d p [ 3 ] [ 22 − 1 ∗ 2 ] d p [ 3 ] [ 22 − 2 ∗ 2 ] + d p [ 3 ] [ 22 − 3 ∗ 2 ] + d p [ 3 ] [ 22 − 4 ∗ 2 ] + d p [ 3 ] [ 22 − z h a n g [ i d x ] ∗ 2 ] dp[2][22] = dp[3][22 - 0 * 2] + dp[3][22 - 1 * 2] dp[3][22 - 2 * 2] + dp[3][22 - 3* 2] + dp[3][22 - 4 * 2] + dp[3][22 - zhang[idx] * 2] dp[2][22]=dp[3][2202]+dp[3][2212]dp[3][2222]+dp[3][2232]+dp[3][2242]+dp[3][22zhang[idx]2]
  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − 0 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 1 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 2 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 3 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − 4 ∗ c o i n s [ i d x ] ] + d p [ 3 ] [ 22 − z h a n g [ i d x ] ∗ c o i n s [ i d x ] ] dp[2][22] = dp[3][22 - 0 * coins[idx]] + dp[3][22 - 1 * coins[idx]] + dp[3][22 - 2 * coins[idx]] + dp[3][22 - 3 * coins[idx]]+ dp[3][22 - 4 * coins[idx]]+ dp[3][22 - zhang[idx] * coins[idx]] dp[2][22]=dp[3][220coins[idx]]+dp[3][221coins[idx]]+dp[3][222coins[idx]]+dp[3][223coins[idx]]+dp[3][224coins[idx]]+dp[3][22zhang[idx]coins[idx]]

相当于:

  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 − ( 0 + 1 + 2 + . . . . + z h a n g [ i d x ] ) ∗ c o i n s [ i d x ] ] dp[2][22] = dp[3][22 - (0+1+2+....+zhang[idx])* coins[idx]] dp[2][22]=dp[3][22(0+1+2+....+zhang[idx])coins[idx]]

从:

  • d p [ 2 ] [ 22 ] = d p [ 3 ] [ 22 ] + d p [ 2 ] [ 20 ] − d p [ 3 ] [ 10 ] dp[2][22] = dp[3][22] + dp[2][20] - dp[3][10] dp[2][22]=dp[3][22]+dp[2][20]dp[3][10]

推广:

  • d p [ i d x ] [ r e s t ] = d p [ i d x + 1 ] [ r e s t ] + d p [ i d x ] [ r e s t − c o i n s [ i d x ] ] − d p [ i d x + 1 ] [ r e s t − ( z h a n g [ i d x ] + 1 ) ∗ c o i n s [ i d x ] ] dp[idx][rest] = dp[idx + 1][rest] + dp[idx][rest - coins[idx]] - dp[idx + 1][rest - (zhang[idx] + 1) * coins[idx]] dp[idx][rest]=dp[idx+1][rest]+dp[idx][restcoins[idx]]dp[idx+1][rest(zhang[idx]+1)coins[idx]]
class Solution {
    struct Info{
        std::vector<int> coins;
        std::vector<int> zhangs;
    };

    Info getInfos(vector<int>& coins){
        std::map<int, int> mapper;
        for(auto i : coins){
            ++mapper[i];
        }

        Info info;
        for(auto i : mapper){
            info.coins.emplace_back(i.first);
            info.zhangs.emplace_back(i.second);
        }
        return info;
    }

    
public:
    int coinsWay(vector<int>& moneys, int amount){
        if(amount < 0){
            return -1;
        }
        if(amount == 0 || moneys.empty()){
            return 0;
        }

        auto item = getInfos(moneys);
        auto coins = item.coins, zhangs = item.zhangs;
        int N = coins.size();
        std::vector<std::vector<int>> dp(N + 1, std::vector<int>(amount + 1, 0));
        dp[N][0] = 1;
        for (int idx = N - 1; idx >= 0; --idx) {
            for (int rest = 0; rest <= amount; ++rest) {
                dp[idx][rest] = dp[idx + 1][rest];
                if(rest - coins[idx] >= 0){
                    dp[idx][rest] += dp[idx][rest - coins[idx]];
                }
                if(rest - (zhangs[idx] + 1) * coins[idx] >= 0){
                    dp[idx][rest] -= dp[idx + 1][rest - (zhangs[idx] + 1) * coins[idx]];
                }
            }
        }

        return dp[0][ amount];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值