{
  "id": "P065",
  "slug": "coin-change",
  "key": "P065-coin-change",
  "title": "Coin change",
  "summary": "The fewest coins for an amount with any set of coin values, by dynamic programming, set against the greedy largest-coin-first way; how many different handfuls make the amount; and whether a coin set is one where greedy is always right, with the first amount where it is not.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P065 - Coin change\n\nThe fewest coins that make an amount, for any set of coin values. They are\nworked out by dynamic programming and set against the greedy way of\ntaking the largest coin that fits. The program also counts how many\ndifferent handfuls make the amount, and says whether a coin set is one\nwhere greedy is always right - and if not, the first amount where it goes\nwrong. It starts with the euro coins: 1, 2, 5, 10, 20, 50, 100 and 200\ncents.\n\n- `main.eml` - the menu, reading amounts and coin sets, and the messages\n- `coins.eml` - fewest coins, greedy, the number of ways, and the first\n  amount greedy gets wrong\n\nHow each part works:\n\n- Fewest coins: as in the corpus case `coin-change-dp`, a table holds the\n  fewest coins for every amount from 1 up. Each is one more than the best\n  of the amounts one coin smaller. Remembering which coin did it lets the\n  coins be read back. This is right for any coin set. With 1, 3 and 4,\n  greedy pays 6 as 4 + 1 + 1, three coins, where 3 + 3 takes two.\n- Greedy may also get stuck: with 5 and 7 it pays 24 as 7 + 7 + 7 and has\n  3 left over, though 7 + 7 + 5 + 5 works.\n- Number of ways: take the coin values one at a time and add, for every\n  amount, the ways to make it without that coin to the ways with it.\n  Each handful is then counted once, whatever order its coins are in.\n- Is greedy safe: search for the first amount where greedy does worse, up\n  to the largest coin plus the next largest. For a set that has a 1, Kozen\n  and Zaks (1994) showed that if greedy ever goes wrong, it first does so\n  below that bound - so no failure there means none at all. For a set\n  without a 1 the program says the search proves nothing beyond the\n  bound.\n\nWhat is checked: menu choices 1 to 5; amounts from 1 to 10000; a coin set\nof 1 to 10 different values from 1 to 1000, in any order. An empty answer\ncancels.\n\nSessions: `sessions/basic.in` gives:\n- 289 in euro cents: 7 coins either way;\n- 73,682 ways to make 200 from the euro coins, and the euro set checked\n  as greedy-safe;\n- the set 1, 3, 4: 6 takes 2 coins, and greedy's 3 coins is its first\n  failure;\n- the set 1, 10, 25: greedy first fails at 30, 25 + 5 x 1 against\n  3 x 10, and there are 29 ways to make 100.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- amounts 0, 10001 and abc;\n- the coin sets \"3 3 7\" with a repeated value, \"0 5\", and eleven values;\n- the set 5, 7: 3 cannot be made, greedy gets stuck on 24, and it first\n  goes wrong at 10;\n- a cancelled set, and the single coin 4.\n\nBuilt on the verified corpus case `coin-change-dp` (the fewest-coins table\nfilled from 1 up, right where greedy is not).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P065 coin change: the fewest coins for an amount with any set of coin\n# values, worked out by dynamic programming and set against the greedy\n# \"largest coin first\" way; how many ways there are to make the amount; and\n# whether a coin set is one where greedy is always right.\nimport coins\n\ndef trim(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef number(s):\n    if s == \"\" or len(s) > 6:\n        return -1\n    0 => n\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef words(s):\n    [] => out\n    \"\" => word\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                out + [word] => out\n            \"\" => word\n        else:\n            word + c => word\n    return out\n\ndef handful(used):\n    # [50, 50, 20, 2] -> \"2 x 50 + 20 + 2\"\n    \"\" => s\n    0 => i\n    while i < len(used):\n        i => j\n        while j < len(used) and used[j] == used[i]:\n            j + 1 => j\n        if s != \"\":\n            s + \" + \" => s\n        if j - i > 1:\n            s + str(j - i) + \" x \" + str(used[i]) => s\n        else:\n            s + str(used[i]) => s\n        j => i\n    return s\n\ndef set_text(cs):\n    \"\" => s\n    for c in cs:\n        if s != \"\":\n            s + \", \" => s\n        s + str(c) => s\n    return s\n\ndef counted(n, one, many):\n    if n == 1:\n        return \"1 \" + one\n    return str(n) + \" \" + many\n\ndef ask_amount():\n    while True:\n        trim(input(\"amount (1 to 10000)> \")) => answer\n        if answer == \"\":\n            return -1\n        number(answer) => n\n        if n >= 1 and n <= 10000:\n            return n\n        \"Type a whole amount from 1 to 10000.\" ^0\n\ndef make_change(cs):\n    ask_amount() => a\n    if a == -1:\n        \"Cancelled.\" ^0\n        return\n    coins.fewest(cs, a) => best\n    coins.greedy(cs, a) => g\n    if best[0] == -1:\n        (str(a) + \" cannot be made from \" + set_text(cs) + \".\") ^0\n        return\n    (\"Fewest: \" + counted(best[0], \"coin\", \"coins\") + \", \" + handful(best[1]) + \".\") ^0\n    if g[0] == -1:\n        (\"Greedy gets stuck: after \" + handful(g[1]) + \" no coin fits what is left.\") ^0\n    elif g[0] == best[0]:\n        (\"Greedy, largest first, finds the same number: \" + handful(g[1]) + \".\") ^0\n    else:\n        (\"Greedy, largest first, uses \" + str(g[0]) + \": \" + handful(g[1]) + \" - \" + counted(g[0] - best[0], \"coin\", \"coins\") + \" more than needed.\") ^0\n\ndef count_ways(cs):\n    ask_amount() => a\n    if a == -1:\n        \"Cancelled.\" ^0\n        return\n    coins.ways(cs, a) => n\n    (\"There are \" + str(n) + \" different ways to make \" + str(a) + \" from \" + set_text(cs) + \" (the order of the coins does not count).\") ^0\n\ndef greedy_check(cs):\n    coins.first_greedy_miss(cs) => r\n    if len(cs) < 2:\n        \"With one coin value there is nothing to choose.\" ^0\n    elif r[0] == 0:\n        if cs[0] == 1:\n            (\"Greedy is always right for \" + set_text(cs) + \": no amount below \" + str(r[1]) + \" beats it, and a set with a 1 that fails has its first failure below that bound.\") ^0\n        else:\n            (\"Greedy is right for every amount up to \" + str(r[1]) + \" that \" + set_text(cs) + \" can make. Without a 1 coin that bound proves nothing beyond itself.\") ^0\n    else:\n        coins.fewest(cs, r[0]) => best\n        coins.greedy(cs, r[0]) => g\n        if g[0] == -1:\n            (\"Greedy first goes wrong at \" + str(r[0]) + \": it gets stuck after \" + handful(g[1]) + \", but \" + handful(best[1]) + \" works.\") ^0\n        else:\n            (\"Greedy first goes wrong at \" + str(r[0]) + \": \" + handful(g[1]) + \" (\" + str(g[0]) + \") instead of \" + handful(best[1]) + \" (\" + str(best[0]) + \").\") ^0\n\ndef new_set():\n    while True:\n        words(trim(input(\"coin values in any order (like 1 3 4)> \"))) => ws\n        if len(ws) == 0:\n            return []\n        [] => cs\n        True => ok\n        for w in ws:\n            number(w) => n\n            if n < 1 or n > 1000:\n                False => ok\n            else:\n                False => seen\n                for c in cs:\n                    if c == n:\n                        True => seen\n                if seen:\n                    False => ok\n                cs + [n] => cs\n        if ok and len(cs) <= 10:\n            return coins.sorted_down(cs)\n        \"Type 1 to 10 different whole values from 1 to 1000.\" ^0\n\ndef ascending(cs):\n    [] => out\n    for k in [0:len(cs) - 1]:\n        [cs[k]] + out => out\n    return out\n\n\"== Coin change ==\" ^0\n\"The fewest coins for an amount, with any coin values - and when taking the largest coin first is wrong.\" ^0\n[1, 2, 5, 10, 20, 50, 100, 200] => cs\n(\"Coins: \" + set_text(cs) + \" (euro cents).\") ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        make_change(cs)\n    elif choice == \"2\":\n        count_ways(cs)\n    elif choice == \"3\":\n        greedy_check(cs)\n    elif choice == \"4\":\n        new_set() => n\n        if len(n) == 0:\n            \"Cancelled.\" ^0\n        else:\n            ascending(n) => cs\n            (\"Coins: \" + set_text(cs) + \".\") ^0\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n\"Bye.\" ^0\n",
      "python": "import coins\n\ndef trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef number(s):\n    if s == \"\" or len(s) > 6:\n        return -1\n    n = 0\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef words(s):\n    out = []\n    word = \"\"\n    for c in s + \" \":\n        if c == \" \" or c == \",\":\n            if word != \"\":\n                out = out + [word]\n            word = \"\"\n        else:\n            word = word + c\n    return out\n\ndef handful(used):\n    s = \"\"\n    i = 0\n    while i < len(used):\n        j = i\n        while j < len(used) and used[j] == used[i]:\n            j = j + 1\n        if s != \"\":\n            s = s + \" + \"\n        if j - i > 1:\n            s = s + str(j - i) + \" x \" + str(used[i])\n        else:\n            s = s + str(used[i])\n        i = j\n    return s\n\ndef set_text(cs):\n    s = \"\"\n    for c in cs:\n        if s != \"\":\n            s = s + \", \"\n        s = s + str(c)\n    return s\n\ndef counted(n, one, many):\n    if n == 1:\n        return \"1 \" + one\n    return str(n) + \" \" + many\n\ndef ask_amount():\n    while True:\n        answer = trim(input(\"amount (1 to 10000)> \"))\n        if answer == \"\":\n            return -1\n        n = number(answer)\n        if n >= 1 and n <= 10000:\n            return n\n        print(\"Type a whole amount from 1 to 10000.\")\n\ndef make_change(cs):\n    a = ask_amount()\n    if a == -1:\n        print(\"Cancelled.\")\n        return\n    best = coins.fewest(cs, a)\n    g = coins.greedy(cs, a)\n    if best[0] == -1:\n        print(str(a) + \" cannot be made from \" + set_text(cs) + \".\")\n        return\n    print(\"Fewest: \" + counted(best[0], \"coin\", \"coins\") + \", \" + handful(best[1]) + \".\")\n    if g[0] == -1:\n        print(\"Greedy gets stuck: after \" + handful(g[1]) + \" no coin fits what is left.\")\n    elif g[0] == best[0]:\n        print(\"Greedy, largest first, finds the same number: \" + handful(g[1]) + \".\")\n    else:\n        print(\"Greedy, largest first, uses \" + str(g[0]) + \": \" + handful(g[1]) + \" - \" + counted(g[0] - best[0], \"coin\", \"coins\") + \" more than needed.\")\n\ndef count_ways(cs):\n    a = ask_amount()\n    if a == -1:\n        print(\"Cancelled.\")\n        return\n    n = coins.ways(cs, a)\n    print(\"There are \" + str(n) + \" different ways to make \" + str(a) + \" from \" + set_text(cs) + \" (the order of the coins does not count).\")\n\ndef greedy_check(cs):\n    r = coins.first_greedy_miss(cs)\n    if len(cs) < 2:\n        print(\"With one coin value there is nothing to choose.\")\n    elif r[0] == 0:\n        if cs[0] == 1:\n            print(\"Greedy is always right for \" + set_text(cs) + \": no amount below \" + str(r[1]) + \" beats it, and a set with a 1 that fails has its first failure below that bound.\")\n        else:\n            print(\"Greedy is right for every amount up to \" + str(r[1]) + \" that \" + set_text(cs) + \" can make. Without a 1 coin that bound proves nothing beyond itself.\")\n    else:\n        best = coins.fewest(cs, r[0])\n        g = coins.greedy(cs, r[0])\n        if g[0] == -1:\n            print(\"Greedy first goes wrong at \" + str(r[0]) + \": it gets stuck after \" + handful(g[1]) + \", but \" + handful(best[1]) + \" works.\")\n        else:\n            print(\"Greedy first goes wrong at \" + str(r[0]) + \": \" + handful(g[1]) + \" (\" + str(g[0]) + \") instead of \" + handful(best[1]) + \" (\" + str(best[0]) + \").\")\n\ndef new_set():\n    while True:\n        ws = words(trim(input(\"coin values in any order (like 1 3 4)> \")))\n        if len(ws) == 0:\n            return []\n        cs = []\n        ok = True\n        for w in ws:\n            n = number(w)\n            if n < 1 or n > 1000:\n                ok = False\n            else:\n                seen = False\n                for c in cs:\n                    if c == n:\n                        seen = True\n                if seen:\n                    ok = False\n                cs = cs + [n]\n        if ok and len(cs) <= 10:\n            return coins.sorted_down(cs)\n        print(\"Type 1 to 10 different whole values from 1 to 1000.\")\n\ndef ascending(cs):\n    out = []\n    for k in range(0, len(cs)):\n        out = [cs[k]] + out\n    return out\n\nprint(\"== Coin change ==\")\nprint(\"The fewest coins for an amount, with any coin values - and when taking the largest coin first is wrong.\")\ncs = [1, 2, 5, 10, 20, 50, 100, 200]\nprint(\"Coins: \" + set_text(cs) + \" (euro cents).\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        make_change(cs)\n    elif choice == \"2\":\n        count_ways(cs)\n    elif choice == \"3\":\n        greedy_check(cs)\n    elif choice == \"4\":\n        n = new_set()\n        if len(n) == 0:\n            print(\"Cancelled.\")\n        else:\n            cs = ascending(n)\n            print(\"Coins: \" + set_text(cs) + \".\")\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "coins.eml",
      "eml": "# P065 coin change - fewest coins by dynamic programming, the greedy way\n# for comparison, and the number of ways. A coin set is a list of distinct\n# values from smallest to largest; amounts are whole units.\n\ndef fewest(coins, amount):\n    # The corpus case coin-change-dp's table, best[v] = the fewest coins that\n    # make v, filled from 1 up: best[v] = 1 + the smallest best[v - c] over\n    # the coins c that fit. last[v] keeps the coin that did it, so the coins\n    # can be read back. Returns [count, coins used largest first], or [-1, []]\n    # when no combination makes the amount.\n    -1 => none\n    [none] * (amount + 1) => best\n    [0] * (amount + 1) => last\n    0 => best[0]\n    for v in [1:amount]:\n        for c in coins:\n            if c <= v and best[v - c] != none:\n                if best[v] == none or best[v - c] + 1 < best[v]:\n                    best[v - c] + 1 => best[v]\n                    c => last[v]\n    if best[amount] == none:\n        return [-1, []]\n    [] => used\n    amount => v\n    while v > 0:\n        used + [last[v]] => used\n        v - last[v] => v\n    return [best[amount], sorted_down(used)]\n\ndef sorted_down(xs):\n    xs[0:len(xs)] => out\n    for i in [1:len(out) - 1]:\n        out[i] => x\n        i => j\n        while j > 0 and out[j - 1] < x:\n            out[j - 1] => out[j]\n            j - 1 => j\n        x => out[j]\n    return out\n\ndef greedy(coins, amount):\n    # Always the largest coin that still fits. Returns [count, coins used],\n    # or [-1, coins used so far] when it gets stuck short of the amount.\n    [] => used\n    amount => left\n    len(coins) - 1 => k\n    while left > 0 and k >= 0:\n        if coins[k] <= left:\n            used + [coins[k]] => used\n            left - coins[k] => left\n        else:\n            k - 1 => k\n    if left > 0:\n        return [-1, used]\n    return [len(used), used]\n\ndef ways(coins, amount):\n    # How many different handfuls make the amount, order not counting: take\n    # the coins one value at a time, ways[v] += ways[v - c], so each handful\n    # is counted once, in the order of the coin set.\n    [0] * (amount + 1) => w\n    1 => w[0]\n    for c in coins:\n        for v in [c:amount]:\n            w[v] + w[v - c] => w[v]\n    return w[amount]\n\ndef first_greedy_miss(coins):\n    # The smallest amount where greedy does worse than the fewest coins, or\n    # gets stuck where coins could make it - searched up to the largest coin\n    # plus the next largest. For a set with a 1, a miss exists only if one\n    # is below that bound (Kozen and Zaks, 1994). Returns [amount, bound] or\n    # [0, bound].\n    if len(coins) < 2:\n        return [0, 0]\n    coins[len(coins) - 1] + coins[len(coins) - 2] => bound\n    -1 => none\n    [none] * (bound + 1) => best\n    0 => best[0]\n    for v in [1:bound]:\n        for c in coins:\n            if c <= v and best[v - c] != none:\n                if best[v] == none or best[v - c] + 1 < best[v]:\n                    best[v - c] + 1 => best[v]\n        if best[v] != none:\n            greedy(coins, v) => g\n            if g[0] == -1 or g[0] > best[v]:\n                return [v, bound]\n    return [0, bound]\n",
      "python": "def fewest(coins, amount):\n    none = -1\n    best = [none] * (amount + 1)\n    last = [0] * (amount + 1)\n    best[0] = 0\n    for v in range(1, amount+1):\n        for c in coins:\n            if c <= v and best[v - c] != none:\n                if best[v] == none or best[v - c] + 1 < best[v]:\n                    best[v] = best[v - c] + 1\n                    last[v] = c\n    if best[amount] == none:\n        return [-1, []]\n    used = []\n    v = amount\n    while v > 0:\n        used = used + [last[v]]\n        v = v - last[v]\n    return [best[amount], sorted_down(used)]\n\ndef sorted_down(xs):\n    out = xs[0:len(xs)]\n    for i in range(1, len(out)):\n        x = out[i]\n        j = i\n        while j > 0 and out[j - 1] < x:\n            out[j] = out[j - 1]\n            j = j - 1\n        out[j] = x\n    return out\n\ndef greedy(coins, amount):\n    used = []\n    left = amount\n    k = len(coins) - 1\n    while left > 0 and k >= 0:\n        if coins[k] <= left:\n            used = used + [coins[k]]\n            left = left - coins[k]\n        else:\n            k = k - 1\n    if left > 0:\n        return [-1, used]\n    return [len(used), used]\n\ndef ways(coins, amount):\n    w = [0] * (amount + 1)\n    w[0] = 1\n    for c in coins:\n        for v in range(c, amount+1):\n            w[v] = w[v] + w[v - c]\n    return w[amount]\n\ndef first_greedy_miss(coins):\n    if len(coins) < 2:\n        return [0, 0]\n    bound = coins[len(coins) - 1] + coins[len(coins) - 2]\n    none = -1\n    best = [none] * (bound + 1)\n    best[0] = 0\n    for v in range(1, bound+1):\n        for c in coins:\n            if c <= v and best[v - c] != none:\n                if best[v] == none or best[v - c] + 1 < best[v]:\n                    best[v] = best[v - c] + 1\n        if best[v] != none:\n            g = greedy(coins, v)\n            if g[0] == -1 or g[0] > best[v]:\n                return [v, bound]\n    return [0, bound]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\n0\n10001\nabc\n\n4\n3 3 7\n0 5\n1 2 3 4 5 6 7 8 9 10 11\n5 7\n1\n3\n1\n24\n3\n4\n\n4\n4\n3\n5\n",
      "screen": "== Coin change ==\nThe fewest coins for an amount, with any coin values - and when taking the largest coin first is wrong.\nCoins: 1, 2, 5, 10, 20, 50, 100, 200 (euro cents).\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 1\namount (1 to 10000)> 0\nType a whole amount from 1 to 10000.\namount (1 to 10000)> 10001\nType a whole amount from 1 to 10000.\namount (1 to 10000)> abc\nType a whole amount from 1 to 10000.\namount (1 to 10000)> \nCancelled.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 4\ncoin values in any order (like 1 3 4)> 3 3 7\nType 1 to 10 different whole values from 1 to 1000.\ncoin values in any order (like 1 3 4)> 0 5\nType 1 to 10 different whole values from 1 to 1000.\ncoin values in any order (like 1 3 4)> 1 2 3 4 5 6 7 8 9 10 11\nType 1 to 10 different whole values from 1 to 1000.\ncoin values in any order (like 1 3 4)> 5 7\nCoins: 5, 7.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 1\namount (1 to 10000)> 3\n3 cannot be made from 5, 7.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 1\namount (1 to 10000)> 24\nFewest: 4 coins, 2 x 7 + 2 x 5.\nGreedy gets stuck: after 3 x 7 no coin fits what is left.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 3\nGreedy first goes wrong at 10: it gets stuck after 7, but 2 x 5 works.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 4\ncoin values in any order (like 1 3 4)> \nCancelled.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 4\ncoin values in any order (like 1 3 4)> 4\nCoins: 4.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 3\nWith one coin value there is nothing to choose.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n289\n2\n200\n3\n4\n1 3 4\n1\n6\n3\n4\n25 10 1\n3\n1\n30\n2\n100\n5\n",
      "screen": "== Coin change ==\nThe fewest coins for an amount, with any coin values - and when taking the largest coin first is wrong.\nCoins: 1, 2, 5, 10, 20, 50, 100, 200 (euro cents).\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 1\namount (1 to 10000)> 289\nFewest: 7 coins, 200 + 50 + 20 + 10 + 5 + 2 x 2.\nGreedy, largest first, finds the same number: 200 + 50 + 20 + 10 + 5 + 2 x 2.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 2\namount (1 to 10000)> 200\nThere are 73682 different ways to make 200 from 1, 2, 5, 10, 20, 50, 100, 200 (the order of the coins does not count).\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 3\nGreedy is always right for 1, 2, 5, 10, 20, 50, 100, 200: no amount below 300 beats it, and a set with a 1 that fails has its first failure below that bound.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 4\ncoin values in any order (like 1 3 4)> 1 3 4\nCoins: 1, 3, 4.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 1\namount (1 to 10000)> 6\nFewest: 2 coins, 2 x 3.\nGreedy, largest first, uses 3: 4 + 2 x 1 - 1 coin more than needed.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 3\nGreedy first goes wrong at 6: 4 + 2 x 1 (3) instead of 2 x 3 (2).\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 4\ncoin values in any order (like 1 3 4)> 25 10 1\nCoins: 1, 10, 25.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 3\nGreedy first goes wrong at 30: 25 + 5 x 1 (6) instead of 3 x 10 (3).\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 1\namount (1 to 10000)> 30\nFewest: 3 coins, 3 x 10.\nGreedy, largest first, uses 6: 25 + 5 x 1 - 3 coins more than needed.\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 2\namount (1 to 10000)> 100\nThere are 29 different ways to make 100 from 1, 10, 25 (the order of the coins does not count).\n\n1) fewest coins  2) number of ways  3) is greedy safe?  4) new coin set  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "coin-change-dp",
      "caseId": "082-coin-change-dp",
      "title": "Coin change (dynamic programming)"
    }
  ],
  "updated": "2026-10-14"
}
