diff --git a/config.json b/config.json index 14a10c8a..385fc9c8 100644 --- a/config.json +++ b/config.json @@ -984,6 +984,14 @@ "prerequisites": [], "difficulty": 6 }, + { + "slug": "knapsack", + "name": "Knapsack", + "uuid": "e59c633c-f5d1-45e6-bfb3-b32f0bb12f18", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "book-store", "name": "Book Store", 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/Knapsack.example.ps1 b/exercises/practice/knapsack/.meta/Knapsack.example.ps1 new file mode 100644 index 00000000..53044462 --- /dev/null +++ b/exercises/practice/knapsack/.meta/Knapsack.example.ps1 @@ -0,0 +1,47 @@ +Function Get-MaximumValue() { + <# + .SYNOPSIS + Implement a function to solve the classic knapsack problem. + + .DESCRIPTION + Given a knapsack with a specific carrying capacity (W), determine the maximum value we can get from the list of items. + Note that each item can only be taken once. + + All values given will be strictly positive. + + .PARAMETER MaxWeight + An integer represent the maximum weight to be carried. + + .PARAMETER Items + An array of object represent the items, each object will have a Weight and a Value property. + + .EXAMPLE + $items = @( + [PSCustomObject]@{Weight = 1; Value = 3} + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 3; Value = 7} + [PSCustomObject]@{Weight = 4; Value = 8} + ) + + Get-MaximumValue -MaxWeight 5 -Items $items + Returns: 12 + #> + [CmdletBinding()] + Param( + [int]$MaxWeight, + [object[]]$Items + ) + if (-not $Items.Count) {return 0} + $table = 0..$Items.Count | ForEach-Object { ,(@(0) * ($MaxWeight + 1)) } + + for ($i = 0; $i -le $Items.Count; $i++) { + for ($j = 0; $j -le $MaxWeight; $j++) { + if ($Items[$i].Weight -le $j) { + $table[$i][$j] = [math]::Max($table[$i-1][$j], $table[$i-1][$j-$Items[$i].Weight] + $Items[$i].Value) + }else{ + $table[$i][$j] = $table[$i-1][$j] + } + } + } + $table[$Items.Count - 1][$MaxWeight] +} \ No newline at end of file diff --git a/exercises/practice/knapsack/.meta/config.json b/exercises/practice/knapsack/.meta/config.json new file mode 100644 index 00000000..a4c31665 --- /dev/null +++ b/exercises/practice/knapsack/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glaxxie" + ], + "files": { + "solution": [ + "Knapsack.ps1" + ], + "test": [ + "Knapsack.tests.ps1" + ], + "example": [ + ".meta/Knapsack.example.ps1" + ] + }, + "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 00000000..febc7b26 --- /dev/null +++ b/exercises/practice/knapsack/.meta/tests.toml @@ -0,0 +1,31 @@ +# 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" + +[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.ps1 b/exercises/practice/knapsack/Knapsack.ps1 new file mode 100644 index 00000000..85337baa --- /dev/null +++ b/exercises/practice/knapsack/Knapsack.ps1 @@ -0,0 +1,35 @@ +Function Get-MaximumValue() { + <# + .SYNOPSIS + Implement a function to solve the classic knapsack problem. + + .DESCRIPTION + Given a knapsack with a specific carrying capacity (W), determine the maximum value we can get from the list of items. + Note that each item can only be taken once. + + All values given will be strictly positive. + + .PARAMETER MaxWeight + An integer represent the maximum weight to be carried. + + .PARAMETER Items + An array of object represent the items, each object will have a Weight and a Value property. + + .EXAMPLE + $items = @( + [PSCustomObject]@{Weight = 1; Value = 3} + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 3; Value = 7} + [PSCustomObject]@{Weight = 4; Value = 8} + ) + + Get-MaximumValue -MaxWeight 5 -Items $items + Returns: 12 + #> + [CmdletBinding()] + Param( + [int]$MaxWeight, + [object[]]$Items + ) + Throw "Please implement this function" +} \ No newline at end of file diff --git a/exercises/practice/knapsack/Knapsack.tests.ps1 b/exercises/practice/knapsack/Knapsack.tests.ps1 new file mode 100644 index 00000000..48e7a6f1 --- /dev/null +++ b/exercises/practice/knapsack/Knapsack.tests.ps1 @@ -0,0 +1,106 @@ +BeforeAll { + . "./Knapsack.ps1" +} + +Describe "Knapsack test cases" { + It "no items" { + $items = @() + $got = Get-MaximumValue -MaxWeight 100 -Items $items + $want = 0 + + $got | Should -BeExactly $want + } + + It "one item, too heavy" { + $items = @( + [PSCustomObject]@{Weight = 100; Value = 1} + ) + $got = Get-MaximumValue -MaxWeight 10 -Items $items + $want = 0 + + $got | Should -BeExactly $want + } + + It "five items (cannot be greedy by weight)" { + $items = @( + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 10; Value = 21} + ) + $got = Get-MaximumValue -MaxWeight 10 -Items $items + $want = 21 + + $got | Should -BeExactly $want + } + + It "five items (cannot be greedy by value)" { + $items = @( + [PSCustomObject]@{Weight = 2; Value = 20} + [PSCustomObject]@{Weight = 2; Value = 20} + [PSCustomObject]@{Weight = 2; Value = 20} + [PSCustomObject]@{Weight = 2; Value = 20} + [PSCustomObject]@{Weight = 10; Value = 50} + ) + $got = Get-MaximumValue -MaxWeight 10 -Items $items + $want = 80 + + $got | Should -BeExactly $want + } + + It "example knapsack" { + $items = @( + [PSCustomObject]@{Weight = 5; Value = 10} + [PSCustomObject]@{Weight = 4; Value = 40} + [PSCustomObject]@{Weight = 6; Value = 30} + [PSCustomObject]@{Weight = 4; Value = 50} + ) + $got = Get-MaximumValue -MaxWeight 10 -Items $items + $want = 90 + + $got | Should -BeExactly $want + } + + It "8 items" { + $items = @( + [PSCustomObject]@{Weight = 25; Value = 350} + [PSCustomObject]@{Weight = 35; Value = 400} + [PSCustomObject]@{Weight = 45; Value = 450} + [PSCustomObject]@{Weight = 5; Value = 20} + [PSCustomObject]@{Weight = 25; Value = 70} + [PSCustomObject]@{Weight = 3; Value = 8} + [PSCustomObject]@{Weight = 2; Value = 5} + [PSCustomObject]@{Weight = 2; Value = 5} + ) + $got = Get-MaximumValue -MaxWeight 104 -Items $items + $want = 900 + + $got | Should -BeExactly $want + } + + It "15 items" { + $items = @( + [PSCustomObject]@{Weight = 70; Value = 135} + [PSCustomObject]@{Weight = 73; Value = 139} + [PSCustomObject]@{Weight = 77; Value = 149} + [PSCustomObject]@{Weight = 80; Value = 150} + [PSCustomObject]@{Weight = 82; Value = 156} + [PSCustomObject]@{Weight = 87; Value = 163} + [PSCustomObject]@{Weight = 90; Value = 173} + [PSCustomObject]@{Weight = 94; Value = 184} + [PSCustomObject]@{Weight = 98; Value = 192} + [PSCustomObject]@{Weight = 106; Value = 201} + [PSCustomObject]@{Weight = 110; Value = 210} + [PSCustomObject]@{Weight = 113; Value = 214} + [PSCustomObject]@{Weight = 115; Value = 221} + [PSCustomObject]@{Weight = 118; Value = 229} + [PSCustomObject]@{Weight = 120; Value = 240} + ) + $got = Get-MaximumValue -MaxWeight 750 -Items $items + $want = 1458 + + $got | Should -BeExactly $want + } + +}