计算硬币数量

时间:2013-12-26 14:08:50

标签: javascript

问:我需要支付49'假货币'。我有1,2,3,4和5面额的硬币,我可以支付最多15个硬币的金额。让 M 支付方式。找到M的最后3位数。


所以我用javascript编写了一个解决方案:

function pay() {
var waysOfPaying= 0;
for (e = 0; e < 10; e++) {
    for (d = 0; d < 13; d++) {
        for (c = 0; c < 16; c++) {
            for (b = 0; b < 16; b++) {
                for (a = 0; a < 16; a++) {
                    if ((a + b + c + d + e <= 15) && (a + (2 * b) + (3 * c) + (4 * d) + (5 * e) == 49)) {
                        waysOfPaying++;
                        }
                    }
                }
            }
        }
    }
    return waysOfPaying % 1000 ;
}

我的代码给出的答案是333但是正确答案是714.我做错了什么?

3 个答案:

答案 0 :(得分:2)

您的算法面向每个硬币的价值。问题在于它失去了秩序的重要性:它发现9个值为5的硬币加上1个值为4的硬币加起来为49.但它错过了8个硬币值为5的事实,其次是乘以1,值为4,接着是另外5,也加起来为49。

最初的问题是基于从太空移动到太空,建立一个移动到方格50的轨迹。关注你的位置,而不是跳跃值。想想在每个空间做出的决定:   - 你在50号太空吗?如果是这样,你找到了一条有效的踪迹,算上它。   - 你过了49号广场,或者你有15次搬到这里?如果是,则该路径结束,并且没有任何进一步的跳跃。   - 如果不是,则可以进行5次可能的移动:跳过1,2,3,4或5个空格。在每一个之后,再次评估你的位置。

提示:使用递归函数模拟您在空间上的操作。

答案 1 :(得分:2)

此问题也发布在cs.stackexchange中。 我从那里添加了我的答案副本:

https://cs.stackexchange.com/questions/19304/calculating-number-of-ways-of-paying-with-coins/19305?noredirect=1#comment38911_19305

我会用动态编程来解决它。无论如何,你的代码对我来说很好。您将查看所有选项,并计算满足条件的那些选项。

我运行了你的脚本,我看到选项的数量正好是333.如果这真的是答案,那么为什么在这个问题中你被要求给出最后三位数?

我想,也许你需要计算选项并考虑内在的顺序。

例如:5,5,5,5,5,5,5,5,5,4将作为选项计算,并且4,5,5,5,5,5,5,5,5 ,5将被视为另一种选择。

在这种情况下,选项的数量会更高,并且要求最后三位数是有意义的。

您可以通过计算满足条件的每个元组(a,b,c,d,e)的排列数(注意有相同的元素),轻松地将代码更改为此版本的问题。它比回顾所有选项更有效率。

答案 2 :(得分:0)

正如人们之前所指出的那样,由于订单很重要,您想要回答的问题与所述问题不同。你给出的解决方案是正确的,没有排列(333)。但是,我不认为尝试所有选项都是解决这个问题的好方法。

如果您有兴趣看到可以在JavaScript中实现,请参阅下文:

function pay (target, maxCoins, partial) {
    function sumArray (array) {
        var sum = 0;
        for (var i = 0; i < array.length; i++) {
           sum += array[i];
        }
        return sum;
    }

    if (typeof target === 'undefined')
        target = 49;
    if (typeof maxCoins === 'undefined')
        maxCoins = 15;
    if (!partial)
        partial = [];

    var sum = sumArray(partial);
    if (sum === target) {
        return 1;
    } else if (sum < target && partial.length < maxCoins) {
        var childSolutions = 0;
        for (var next = 1; next <= 5; next++) {
            var copy = partial.slice(0);
            copy.push(next);
            childSolutions += pay(target, copy);
        }
        return childSolutions % 1000; 
    }
    return 0;
}

不知道这实际需要多长时间才能运行(我在几个小时后放弃了!)。有效解决问题的诀窍是做你做过的事情,但对于你找到的每个解决方案,找出硬币可以重新排列的方式。幸运的是有一个well-known formula for this(参见“Multiset位”)。下面是您的代码如何适应包含排列..

var factorials = [1 , 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000];

function permutations (a, b, c, d, e) {
    var n = a + b + c + d + e;
    var base = 1;

    for (var i = 0; i < 5; i++) {
        var arg = arguments[i];
        if (arg > 0)
            base *= factorials[arg - 1];
    }

    return n < 1 ? 1 : factorials[n - 1] / base ;
}

function pay() {
    var a, b, c, d, e,
        waysOfPaying = 0;

    for (e = 0; e < 10; e++) {
        for (d = 0; d < 13; d++) {
            for (c = 0; c < 16; c++) {
                for (b = 0; b < 16; b++) {
                    for (a = 0; a < 16; a++) {
                        if ((a + b + c + d + e <= 15) && (a + (2 * b) + (3 * c) + (4 * d) + (5 * e) == 49)) {
                            waysOfPaying += permutations(a, b, c, d, e);
                        }
                    }
                }
            }
        }
    }
    return waysOfPaying % 1000 ;
}

如果您运行,则为您提供您期望的值714。