Project Euler 31- Coin sums

题目描述

有面值分别为1,2,5,10,20,50,100,200的硬币,现要凑齐200的面值,请问一共有多少种凑法。


问题分析

不正确的解法

直接想到的方法是使用动规:
状态转换方程:f(x) = sum { f(x - a[i]) }
注:a[i]为各种面值

# Coin sums
COINS = [1, 2, 5, 10, 20, 50, 100, 200]
memorandum = {}


def calculate(currency):
    if currency < 0:
        return 0
    elif currency == 0:
        return 1
    # if memorandum has, return value
    elif currency in memorandum:
        return memorandum[currency]
    else:
        global COINS
        result = 0
        for coin in COINS:
            result += calculate(currency - coin)
        # set this value to memorandum
        memorandum[currency] = result


if __name__ == '__main__':
    for i in xrange(200 + 1):
        calculate(i)
    for ele in memorandum:
        print(str(ele) + ' : ' + str(memorandum[ele]))

但我们仔细想一下就会发现一点问题。如果当前的面值为3,那么1+2与2+1都会被看作是可行的解,但实际上这两个是同一种找零。
这样的答案肯定是不对的。

问题的原因

仔细想一下就会发现,出现这个问题的原因在于我们同时使用了所有的硬币参与动规而没有对此加以约束,那么当前面值下的不同路径子集树可能会出现同一种组合。

如何规避这些重复的结果 ?

一种可行的方法是先假设只有一种硬币,得出一个解,在此之上依次增加硬币的种类,逐一进行替换。
C#代码:

static void Main(string[] args)
        {
            int target = 200;
            int[] coinSizes = { 1, 2, 5, 10, 20, 50, 100, 200 };
            int[] ways = new int[target + 1];
            ways[0] = 1;

            for (int i = 0; i < coinSizes.Length; i++)
            {
                for (int j = coinSizes[i]; j <= target; j++)
                {
                    ways[j] += ways[j - coinSizes[i]];
                }
            }
            Console.WriteLine(ways[200]);
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值