Problem 31 "Coin sums"

In the United Kingdom the currency is made up of pound (£) and pence (p). 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?

問 31 「硬貨の和」

イギリスでは硬貨はポンド£とペンスpがあり,一般的に流通している硬貨は以下の8種類である.

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

以下の方法で£2を作ることが可能である.

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

これらの硬貨を使って£2を作る方法は何通りあるか?

use std::cmp::Ordering;

fn coin_change_combination(payment: usize, coins: &[usize]) -> u32 {
    assert!(payment > 0 && coins.len() > 0);
    let mut table = vec![vec![0u32; payment]; coins.len()];
    for c in 0..table.len() {
        for p in 0..table[c].len() {
            let v_no = if c == 0 { 0u32 } else { table[c - 1][p] };
            let v_we = match (p + 1).partial_cmp(&(coins[c])).expect("NaNs") {
                Ordering::Less => 0u32,
                Ordering::Equal => 1u32,
                Ordering::Greater => table[c][p - coins[c]],
            };
            table[c][p] = v_no + v_we;
        }
    }
    table[coins.len() - 1][payment - 1]
}

fn main() {
    let payment = 200usize;
    let coins = [1usize, 2, 5, 10, 20, 50, 100, 200];
    let comb = coin_change_combination(payment, &coins);

    println!("{}", comb);
    assert_eq!(comb, 73682);
    assert_eq!(coin_change_combination(8, &[1, 3, 5, 7]), 6);
    assert_eq!(coin_change_combination(3, &[1, 2]), 2);
    assert_eq!(coin_change_combination(2, &[1, 2]), 2);
    assert_eq!(coin_change_combination(1, &[1, 2]), 1);
    assert_eq!(coin_change_combination(5, &[2, 3]), 1);
    assert_eq!(coin_change_combination(5, &[1, 2, 3]), 5);
    assert_eq!(coin_change_combination(5, &[1]), 1);
    assert_eq!(coin_change_combination(2, &[3]), 0);
}