diff --git a/config.json b/config.json index 32448b50..9b0cbec8 100644 --- a/config.json +++ b/config.json @@ -979,6 +979,14 @@ "events", "reactive_programming" ] + }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "6cd9b4d2-2274-4b56-98cf-1c820f1da836", + "practices": [], + "prerequisites": [], + "difficulty": 4 } ] }, diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md new file mode 100644 index 00000000..fadcee1b --- /dev/null +++ b/exercises/practice/knapsack/.docs/instructions.md @@ -0,0 +1,35 @@ +# Instructions + +In this exercise, let's try to solve a classic problem. + +Bob is a thief. +After months of careful planning, he finally manages to crack the security systems of a high-class apartment. + +In front of him are many items, each with a value (v) and weight (w). +Bob, of course, wants to maximize the total value he can get; he would gladly take all of the items if he could. +However, to his horror, he realizes that the knapsack he carries with him can only hold so much weight (W). + +Given a knapsack with a specific carrying capacity (W), help Bob determine the maximum value he can get from the items in the house. +Note that Bob can take only one of each item. + +All values given will be strictly positive. +Items will be represented as a list of items. +Each item will have a weight and value. + +For example: + +```none +Items: [ + { "weight": 5, "value": 10 }, + { "weight": 4, "value": 40 }, + { "weight": 6, "value": 30 }, + { "weight": 4, "value": 50 } +] + +Knapsack Limit: 10 +``` + +For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on. + +In this example, Bob should take the second and fourth item to maximize his value, which, in this case, is 90. +He cannot get more than 90 as his knapsack has a weight limit of 10. diff --git a/exercises/practice/knapsack/.meta/config.json b/exercises/practice/knapsack/.meta/config.json new file mode 100644 index 00000000..ed40b317 --- /dev/null +++ b/exercises/practice/knapsack/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "siebenschlaefer" + ], + "files": { + "solution": [ + "knapsack.nim" + ], + "test": [ + "test_knapsack.nim" + ], + "example": [ + ".meta/example.nim" + ] + }, + "blurb": "Given a knapsack that can only carry a certain weight, determine which items to put in the knapsack in order to maximize their combined value.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Knapsack_problem" +} diff --git a/exercises/practice/knapsack/.meta/example.nim b/exercises/practice/knapsack/.meta/example.nim new file mode 100644 index 00000000..93639378 --- /dev/null +++ b/exercises/practice/knapsack/.meta/example.nim @@ -0,0 +1,8 @@ +type Item = tuple[weight: int, value: int] + +proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = + var dp = newSeq[int](maximumWeight + 1) + for item in items: + for weight in countdown(maximumWeight, item.weight): + dp[weight] = max(dp[weight], item.value + dp[weight - item.weight]) + result = dp[maximumWeight] diff --git a/exercises/practice/knapsack/.meta/tests.toml b/exercises/practice/knapsack/.meta/tests.toml new file mode 100644 index 00000000..8e013ef1 --- /dev/null +++ b/exercises/practice/knapsack/.meta/tests.toml @@ -0,0 +1,36 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a4d7d2f0-ad8a-460c-86f3-88ba709d41a7] +description = "no items" +include = false + +[3993a824-c20e-493d-b3c9-ee8a7753ee59] +description = "no items" +reimplements = "a4d7d2f0-ad8a-460c-86f3-88ba709d41a7" + +[1d39e98c-6249-4a8b-912f-87cb12e506b0] +description = "one item, too heavy" + +[833ea310-6323-44f2-9d27-a278740ffbd8] +description = "five items (cannot be greedy by weight)" + +[277cdc52-f835-4c7d-872b-bff17bab2456] +description = "five items (cannot be greedy by value)" + +[81d8e679-442b-4f7a-8a59-7278083916c9] +description = "example knapsack" + +[f23a2449-d67c-4c26-bf3e-cde020f27ecc] +description = "8 items" + +[7c682ae9-c385-4241-a197-d2fa02c81a11] +description = "15 items" diff --git a/exercises/practice/knapsack/knapsack.nim b/exercises/practice/knapsack/knapsack.nim new file mode 100644 index 00000000..66bd2ca8 --- /dev/null +++ b/exercises/practice/knapsack/knapsack.nim @@ -0,0 +1,4 @@ +type Item = tuple[weight: int, value: int] + +proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = + discard diff --git a/exercises/practice/knapsack/test_knapsack.nim b/exercises/practice/knapsack/test_knapsack.nim new file mode 100644 index 00000000..1c872fc1 --- /dev/null +++ b/exercises/practice/knapsack/test_knapsack.nim @@ -0,0 +1,64 @@ +import unittest +import knapsack + +suite "knapsack": + test "no items": + const maximumWeight = 100 + const items: array[0, tuple[weight: int, value: int]] = [] + const expected = 0 + check maximumValue(maximumWeight, items) == expected + + test "one item, too heavy": + const maximumWeight = 10 + const items = [(weight: 100, value: 1)] + const expected = 0 + check maximumValue(maximumWeight, items) == expected + + test "five items (cannot be greedy by weight)": + const maximumWeight = 10 + const items = [ + (weight: 2, value: 5), (weight: 2, value: 5), (weight: 2, value: 5), + (weight: 2, value: 5), (weight: 10, value: 21) + ] + const expected = 21 + check maximumValue(maximumWeight, items) == expected + + test "five items (cannot be greedy by value)": + const maximumWeight = 10 + const items = [ + (weight: 2, value: 20), (weight: 2, value: 20), (weight: 2, value: 20), + (weight: 2, value: 20), (weight: 10, value: 50) + ] + const expected = 80 + check maximumValue(maximumWeight, items) == expected + + test "example knapsack": + const maximumWeight = 10 + const items = [ + (weight: 5, value: 10), (weight: 4, value: 40), (weight: 6, value: 30), + (weight: 4, value: 50) + ] + const expected = 90 + check maximumValue(maximumWeight, items) == expected + + test "8 items": + const maximumWeight = 104 + const items = [ + (weight: 25, value: 350), (weight: 35, value: 400), (weight: 45, value: 450), + (weight: 5, value: 20), (weight: 25, value: 70), (weight: 3, value: 8), + (weight: 2, value: 5), (weight: 2, value: 5) + ] + const expected = 900 + check maximumValue(maximumWeight, items) == expected + + test "15 items": + const maximumWeight = 750 + const items = [ + (weight: 70, value: 135), (weight: 73, value: 139), (weight: 77, value: 149), + (weight: 80, value: 150), (weight: 82, value: 156), (weight: 87, value: 163), + (weight: 90, value: 173), (weight: 94, value: 184), (weight: 98, value: 192), + (weight: 106, value: 201), (weight: 110, value: 210), (weight: 113, value: 214), + (weight: 115, value: 221), (weight: 118, value: 229), (weight: 120, value: 240) + ] + const expected = 1458 + check maximumValue(maximumWeight, items) == expected