{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Euler Problem 31\n",
    "\n",
    "In England the currency is made up of pound, £, and pence, p, and there are eight coins in general circulation:\n",
    "\n",
    "1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).\n",
    "\n",
    "It is possible to make £2 in the following way:\n",
    "\n",
    "1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p\n",
    "\n",
    "How many different ways can £2 be made using any number of coins?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "Let's do it non-recursive. Tricky part is to use ceil, otherwise we get wrong ranges for example for $\\frac{50}{20}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1]\n",
      "[0, 1, 2]\n"
     ]
    }
   ],
   "source": [
    "from math import ceil\n",
    "\n",
    "print(list(range(50 // 20)))\n",
    "print(list(range(ceil(50 / 20))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "from math import ceil\n",
    "\n",
    "def calculate():\n",
    "    r = 200\n",
    "    c = 0\n",
    "\n",
    "    if r % 200 == 0:\n",
    "        c += 1\n",
    "    for p200 in range(ceil(r / 200)):\n",
    "        r200 = r - p200 * 200\n",
    "        if r200 % 100 == 0:\n",
    "            c += 1\n",
    "        for p100 in range(ceil(r200 / 100)):\n",
    "            r100 = r200 - p100 * 100\n",
    "            if r100 % 50 == 0:\n",
    "                c += 1\n",
    "            for p50 in range(ceil(r100 / 50)):\n",
    "                r50 = r100 - p50 * 50\n",
    "                if r50 % 20 == 0:\n",
    "                    c += 1\n",
    "                for p20 in range(ceil(r50 / 20)):\n",
    "                    r20 = r50 - p20 * 20\n",
    "                    if r20 <= 0:\n",
    "                        break\n",
    "                    if r20 % 10 == 0:\n",
    "                        c += 1\n",
    "                    for p10 in range(ceil(r20 / 10)):\n",
    "                        r10 = r20 - p10 * 10\n",
    "                        if r10 % 5 == 0:\n",
    "                            c += 1\n",
    "                        for p5 in range(ceil(r10 / 5)):\n",
    "                            r5 = r10 - p5 * 5\n",
    "                            if r5 % 2 == 0:\n",
    "                                c += 1\n",
    "                            for p2 in range(ceil(r5 / 2)):\n",
    "                                r2 = r5 - p2 * 2\n",
    "                                if r2 % 1 == 0:\n",
    "                                    c += 1\n",
    "\n",
    "    return c\n",
    "\n",
    "s = calculate()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "73682\n"
     ]
    }
   ],
   "source": [
    "print(s)\n",
    "assert(s == 73682)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I came up with a more concise solution that can be implemented in Scheme. I would like to compare the performance of the solutions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "73682\n"
     ]
    }
   ],
   "source": [
    "def count_change(change, coins):\n",
    "    if not coins:\n",
    "        return 0\n",
    "    count = 0\n",
    "    coin, coins = coins[0], coins[1:]\n",
    "    for i in range(change // coin + 1):\n",
    "        if change - i * coin == 0:\n",
    "            count += 1\n",
    "            continue\n",
    "        if change - i * coin < 0:\n",
    "            break\n",
    "        count += count_change(change - i * coin, coins)\n",
    "    return count\n",
    "\n",
    "def calculate_iterative():\n",
    "    return count_change(200, [200, 100, 50, 20, 10, 5, 2, 1])\n",
    "\n",
    "s = calculate_iterative()\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.16300111500095227\n",
      "11.429953110000497\n"
     ]
    }
   ],
   "source": [
    "import timeit\n",
    "print(timeit.timeit(calculate, number=10))\n",
    "print(timeit.timeit(calculate_iterative, number=10))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Turns out I was way smarter than I thought when I have developped calculate. It checks the remainder and by doing that saves a ton of iterations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "73682\n",
      "0.34602016500139143\n"
     ]
    }
   ],
   "source": [
    "def count_change(change, coins):\n",
    "    count = 0\n",
    "    coin, coins = coins[0], coins[1:]\n",
    "\n",
    "    if change % coin == 0:\n",
    "        count += 1\n",
    "        \n",
    "    if not coins:\n",
    "        return count\n",
    "    \n",
    "    for i in range(ceil(change / coin)):\n",
    "        count += count_change(change - i * coin, coins)\n",
    "    return count\n",
    "\n",
    "def calculate_iterative():\n",
    "    return count_change(200, [200, 100, 50, 20, 10, 5, 2, 1])\n",
    "\n",
    "s = calculate_iterative()\n",
    "print(s)\n",
    "print(timeit.timeit(calculate_iterative, number=10))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "completion_date": "Fri, 25 Aug 2017, 13:02",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python3.6",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "tags": [
   "recursion",
   "coins"
  ]
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
