diff --git a/config.json b/config.json index be78a59cc..2942d5a61 100644 --- a/config.json +++ b/config.json @@ -2149,6 +2149,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "5bfffdf2-95d9-4794-b703-340c253400b2", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ], "foregone": [ diff --git a/exercises/practice/knapsack/.config/dotnet-tools.json b/exercises/practice/knapsack/.config/dotnet-tools.json new file mode 100644 index 000000000..0f7926bad --- /dev/null +++ b/exercises/practice/knapsack/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "fantomas-tool": { + "version": "4.7.9", + "commands": [ + "fantomas" + ] + } + } +} \ No newline at end of file diff --git a/exercises/practice/knapsack/.docs/instructions.md b/exercises/practice/knapsack/.docs/instructions.md new file mode 100644 index 000000000..3411db988 --- /dev/null +++ b/exercises/practice/knapsack/.docs/instructions.md @@ -0,0 +1,25 @@ +# Instructions + +Your task is to determine which items to take so that the total value of his selection is maximized, taking into account the knapsack's carrying capacity. + +Items will be represented as a list of items. +Each item will have a weight and value. +All values given will be strictly positive. +Bob can take only one of each item. + +For example: + +```text +Items: [ + { "weight": 5, "value": 10 }, + { "weight": 4, "value": 40 }, + { "weight": 6, "value": 30 }, + { "weight": 4, "value": 50 } +] + +Knapsack Maximum Weight: 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/.docs/introduction.md b/exercises/practice/knapsack/.docs/introduction.md new file mode 100644 index 000000000..9b2bed8b4 --- /dev/null +++ b/exercises/practice/knapsack/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +Bob is a thief. +After months of careful planning, he finally manages to crack the security systems of a fancy store. + +In front of him are many items, each with a value and weight. +Bob would gladly take all of the items, but his knapsack can only hold so much weight. +Bob has to carefully consider which items to take so that the total value of his selection is maximized. diff --git a/exercises/practice/knapsack/.meta/Example.fs b/exercises/practice/knapsack/.meta/Example.fs new file mode 100644 index 000000000..8e381865c --- /dev/null +++ b/exercises/practice/knapsack/.meta/Example.fs @@ -0,0 +1,13 @@ +module Knapsack + +type Item = { weight: int; value: int } + +let rec maximumValue items maximumWeight = + match items with + | [] -> 0 + | item :: rest when item.weight > maximumWeight -> maximumValue rest maximumWeight + | item :: rest -> + max + (maximumValue rest maximumWeight) + (item.value + + maximumValue rest (maximumWeight - item.weight)) diff --git a/exercises/practice/knapsack/.meta/config.json b/exercises/practice/knapsack/.meta/config.json new file mode 100644 index 000000000..4db8d25e4 --- /dev/null +++ b/exercises/practice/knapsack/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "Knapsack.fs" + ], + "test": [ + "KnapsackTests.fs" + ], + "example": [ + ".meta/Example.fs" + ] + }, + "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/tests.toml b/exercises/practice/knapsack/.meta/tests.toml new file mode 100644 index 000000000..8e013ef19 --- /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.fs b/exercises/practice/knapsack/Knapsack.fs new file mode 100644 index 000000000..e867f30b5 --- /dev/null +++ b/exercises/practice/knapsack/Knapsack.fs @@ -0,0 +1,6 @@ +module Knapsack + +type Item = { weight: int; value: int } + +let rec maximumValue items maximumWeight = + failwith "Please implement the 'maximumValue' function" diff --git a/exercises/practice/knapsack/Knapsack.fsproj b/exercises/practice/knapsack/Knapsack.fsproj new file mode 100644 index 000000000..63024204e --- /dev/null +++ b/exercises/practice/knapsack/Knapsack.fsproj @@ -0,0 +1,22 @@ + + + net8.0 + false + false + true + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + \ No newline at end of file diff --git a/exercises/practice/knapsack/KnapsackTests.fs b/exercises/practice/knapsack/KnapsackTests.fs new file mode 100644 index 000000000..1da45f628 --- /dev/null +++ b/exercises/practice/knapsack/KnapsackTests.fs @@ -0,0 +1,81 @@ +module KnapsackTests + +open FsUnit.Xunit +open Xunit + +open Knapsack + +[] +let ``No items`` () = maximumValue [] 100 |> should equal 0 + +[] +let ``One item, too heavy`` () = + maximumValue [ { weight = 100; value = 1 } ] 10 + |> should equal 0 + +[] +let ``Five items (cannot be greedy by weight)`` () = + maximumValue + [ { weight = 2; value = 5 } + { weight = 2; value = 5 } + { weight = 2; value = 5 } + { weight = 2; value = 5 } + { weight = 10; value = 21 } ] + 10 + |> should equal 21 + +[] +let ``Five items (cannot be greedy by value)`` () = + maximumValue + [ { weight = 2; value = 20 } + { weight = 2; value = 20 } + { weight = 2; value = 20 } + { weight = 2; value = 20 } + { weight = 10; value = 50 } ] + 10 + |> should equal 80 + +[] +let ``Example knapsack`` () = + maximumValue + [ { weight = 5; value = 10 } + { weight = 4; value = 40 } + { weight = 6; value = 30 } + { weight = 4; value = 50 } ] + 10 + |> should equal 90 + +[] +let ``8 items`` () = + maximumValue + [ { 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 } ] + 104 + |> should equal 900 + +[] +let ``15 items`` () = + maximumValue + [ { 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 } ] + 750 + |> should equal 1458 diff --git a/generators/Generators.fs b/generators/Generators.fs index cdaef5f31..8e44dfa01 100644 --- a/generators/Generators.fs +++ b/generators/Generators.fs @@ -2041,3 +2041,6 @@ type SquareRoot() = type EliudsEggs() = inherit ExerciseGenerator() + +type Knapsack() = + inherit ExerciseGenerator()