Project Euler Problem 31

Coin sums

In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation:

        1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).

It is possible to make £2 in the following way:

        1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p

How many different ways can £2 be made using any number of coins?

Link to original description
Source code examples on Github

Erlang version 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p31
% vim:syn=erlang

-mode(compile).

main(_) ->
    Coins  = [1, 2, 5, 10, 20, 50, 100, 200],
    Result = 200,  
    Answer = lists:sum(lists:flatten([f(Result, 0, subcoins(Coins, C), C) || C <- Coins])),
    io:format("Answer ~p ~n", [Answer]).

subcoins(Coins, C)                -> subcoins(Coins, C, []).
subcoins([], _, A)                -> lists:reverse(A);
subcoins([H|T], C, A) when H =< C -> subcoins(T, C, [H] ++ A);
subcoins([_|T], C, A)             -> subcoins(T, C, A).


f(Result, Ac, _, _) when Result =:= Ac -> 1;
f(Result, Ac, _, C) when Result =:= Ac + C -> 1;
f(Result, Ac, _, _) when Result <   Ac -> 0;
f(Result, Ac, Sc, C) -> [f(Result , Ac + C, subcoins(Sc, C1), C1) || C1 <- Sc].

Erlang version 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p31
% vim:syn=erlang

-mode(compile).

main(_) ->
    Coins  = [1, 2, 5, 10, 20, 50, 100, 200],
    Result = 200,  
    Answer = lists:last(t(Coins, [1] ++ [0 || _ <- lists:seq(1, Result)], Result)),
    io:format("Answer ~p ~n", [Answer]).

t([], L, _)            -> L;
t([Coin|T], L, Result) ->
   t(T, f(lists:sublist(L, 1, Coin), Coin, Coin, Result, L), Result).

f(L, E, Coin, R, L1) when E =:= R ->
    L ++ [lists:nth(E + 1, L1) + lists:nth(E - Coin + 1, L)];
f(L, E, Coin, R, L1)              ->
    f(L ++ [lists:nth(E + 1, L1) + lists:nth(E - Coin + 1, L)], E + 1, Coin, R, L1).

Erlang version 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable -sname p31
% vim:syn=erlang

-mode(compile).

main(_) ->
    Coins  = [1, 2, 5, 10, 20, 50, 100, 200],
    Result = 200,  
    io:format("Answer ~p ~n", [t31(Coins, Result)]).

t31(_, 0)            -> 1;
t31([], _)           -> 0;
t31(_, N) when N < 0 -> 0;
t31([C|Cs], N)       -> t31(Cs, N) + t31([C|Cs], N-C).

Python version

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/usr/bin/python

def test31(t, c):
    ways = [1] + [0]*t
    for coin in c:
        for i in range(coin, t+1):
            ways[i] += ways[i-coin]
    return ways[t]

coins = (1, 2, 5, 10, 20, 50, 100, 200)

print test31(200, coins)

Perl version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/perl -w
use strict;

sub test31{
    my ($target, $coins) = @_;

    my @ways = (1) + (0) x $target;
    foreach my $coin ( @$coins ) {
        foreach my $i ( $coin .. $target ){
            $ways[$i] += $ways[$i-$coin]
        }
    }
    $ways[$target]
}

print test31(200, [1, 2, 5, 10, 20, 50, 100, 200])."\n";

Performance

mkh@mkh-xps:~/work/mblog/pr_euler/p31$ time ./p31.erl
Answer 73682 

real    0m0.765s
user    0m0.726s
sys     0m0.067s
mkh@mkh-xps:~/work/mblog/pr_euler/p31$ time ./p31_1.erl                                                                                                        
Answer 73682 

real    0m0.234s
user    0m0.220s
sys     0m0.048s
mkh@mkh-xps:~/work/mblog/pr_euler/p31$ time ./p31_2.erl                                                                                                        
Answer 73682 

real    0m0.754s
user    0m0.750s
sys     0m0.036s
mkh@mkh-xps:~/work/mblog/pr_euler/p31$ time ./p31.py
73682

real    0m0.016s
user    0m0.008s
sys     0m0.008s
mkh@mkh-xps:~/work/mblog/pr_euler/p31$ time ./p31.pl
73682

real    0m0.006s
user    0m0.003s
sys     0m0.003s
mkh@mkh-xps:~/work/mblog/pr_euler/p31$