Tweaked solution 9 a bit, to check all approaches are finding the same set of items master
authorNeil Smith <neil.git@njae.me.uk>
Fri, 12 Oct 2018 10:27:54 +0000 (11:27 +0100)
committerNeil Smith <neil.git@njae.me.uk>
Fri, 12 Oct 2018 10:27:54 +0000 (11:27 +0100)
src/task9/task9.hs
src/task9/task9.ipynb

index dac19e1b58951cd82ec61eff0d20816631ff4549..8a999dff05c7d2ab6daad5814fc199d6c27376b8 100644 (file)
@@ -28,17 +28,22 @@ main = do
         bagsT <- TIO.readFile "data/09-bags.txt"
         let bags = successfulParse bagsT
         let limit = 5000
-        -- print bags
         print $ part1 limit bags
-        print $ part2 limit bags
+        let dpTable = buildTable limit bags
+        print $ part2 dpTable limit bags
+        print $ backtrace dpTable ((length bags), limit)
 
 part1 :: Weight -> [Bag] -> Int
 part1 limit bags = length $ last $ takeWhile (willFit limit) $ inits sortedBags
     where sortedBags = sortBy (compare `on` bagWeight) bags
           willFit limit' bags' = (sum $ map bagWeight bags') < limit'
 
-part2 :: Weight -> [Bag] -> Value
-part2 limit bags = value $ table!(length bags, limit)
+part2 :: DPTable -> Weight -> [Bag] -> Value
+part2 table limit bags = value $ table!(length bags, limit)
+
+
+buildTable :: Weight -> [Bag] -> DPTable
+buildTable limit bags = table
     where initialTable = M.fromList [((0, w), TableEntry {value = 0, backpointer = (0, w)}) | w <- [0..limit]]
           table = foldl' includeBag initialTable 
                           [ (thisBag, bagNumber, allowedWeight) 
@@ -63,6 +68,16 @@ includeBag table (bag, bagNumber, weight) =
           withBag = TableEntry {value = value withBagEntry + bagValue bag, backpointer = withBagKey}
 
 
+backtrace :: DPTable -> (Int, Weight) -> [Bag]
+backtrace table key@(numberBags, weight) 
+    | numberBags == 0       = [Bag { bagValue = 0, bagWeight = weight }]
+    | weight == nextWeight  = backtrace table nextKey
+    | otherwise             = (backtrace table nextKey) ++ [includedBag]
+    where nextKey = backpointer (table!key)
+          (_, nextWeight) = nextKey
+          includedBag = Bag { bagWeight = weight - nextWeight
+                            , bagValue = (value (table!key)) - value (table!nextKey)}
+
 -- Parse the input file
 
 type Parser = Parsec Void Text
index 556ce5efbcdb88dff54bd0bb9381f17f27392724..1852bdd5c7600e14aa9fdb3a679170056ec007c4 100644 (file)
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 66,
    "metadata": {},
    "outputs": [
     {
        "2383"
       ]
      },
-     "execution_count": 16,
+     "execution_count": 66,
      "metadata": {},
      "output_type": "execute_result"
     }
   },
   {
    "cell_type": "code",
-   "execution_count": 60,
+   "execution_count": 69,
    "metadata": {},
    "outputs": [
     {
        "           Element(weight=434, value=195)})"
       ]
      },
-     "execution_count": 60,
+     "execution_count": 69,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "recursive_value(hashable_elements, weight_limit)"
+    "recursive_items = recursive_value(hashable_elements, weight_limit)\n",
+    "recursive_items"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 61,
+   "execution_count": 70,
    "metadata": {},
    "outputs": [
     {
        "2383"
       ]
      },
-     "execution_count": 61,
+     "execution_count": 70,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "sum(e.value for e in recursive_value(hashable_elements, weight_limit))"
+    "sum(e.value for e in recursive_items)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Let's check that these two solutions include the same elements. Use the `backtrace` function to find when new items were added to the optimal order."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 78,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[Element(weight=301, value=134),\n",
+       " Element(weight=314, value=166),\n",
+       " Element(weight=320, value=154),\n",
+       " Element(weight=336, value=190),\n",
+       " Element(weight=337, value=140),\n",
+       " Element(weight=340, value=172),\n",
+       " Element(weight=353, value=191),\n",
+       " Element(weight=356, value=153),\n",
+       " Element(weight=359, value=171),\n",
+       " Element(weight=365, value=177),\n",
+       " Element(weight=381, value=166),\n",
+       " Element(weight=382, value=185),\n",
+       " Element(weight=414, value=189),\n",
+       " Element(weight=434, value=195)]"
+      ]
+     },
+     "execution_count": 78,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dp_items = [element for (pre, post), element in zip(backtrace(vbr).items(), reversed(elements))\n",
+    "             if pre[1] != post[1] ]\n",
+    "dp_items_fs = frozenset(\n",
+    "    Element(weight=e['weight'], value=e['value']) for e in dp_items\n",
+    "    )\n",
+    "sorted(dp_items_fs)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 79,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 79,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "dp_items_fs == recursive_items"
    ]
   },
   {