-
-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add exercise knapsack #563
Open
siebenschlaefer
wants to merge
9
commits into
exercism:main
Choose a base branch
from
siebenschlaefer:add-exercise-knapsack
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+174
−0
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
9b4d1df
Add exercise 'knapsack'
siebenschlaefer 0c849bf
knapsack: Remove empty line at end of file
siebenschlaefer 5621fc5
knapsack: Fix type name
siebenschlaefer d4ad759
knapsack: Fix symbol
siebenschlaefer 4c2fe85
knapsack: fix indentation
siebenschlaefer 529f48d
knapsack: fix indentation
siebenschlaefer ccb1cf9
knapsack: fix indentation
siebenschlaefer 428e6a9
knapsack: fix indentation
siebenschlaefer a60de78
knapsack: use const where possible
siebenschlaefer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
type Item = tuple[weight: int, value: int] | ||
|
||
proc maximumValue*(maximumWeight: int, items: openArray[Item]): int = | ||
discard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should go with an
object
here, although it'll require some other changes.To reduce the verbosity this would otherwise produce in the test file, I think I'd suggest adding a
func
there that takes anopenArray[(int, int)]
and returns a seq ofItem
. Thoughts?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not against this change, but as an inexperienced Nim programmer I want to learn:
Why do you prefer an
object
over atuple
in this case?As for the verbosity: I don't think it's too bad currently but I'm fine with all the alternatives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For myself, the main reason to avoid tuples is because tuples are duck-typed. Consider the following example:
This would compile because a tuple just means a specific ordering of elements. The names of the field (or even if they have names) and the name of the type is not part of the type of the tuple.
The equivalent code for objects, however, would not compile because, even if they do have the same field names and types, because they are 2 different and separate definitions.
This can lead to confusion.
Consider a tuple representing an RGB color and a point in 3-D space. They are interchangeable with each other but don't represent equal values. An object, however, is not interchangeable as such and is therefore not subject to being mistakenly converted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, tuples can be problematic if they get constructed without field names or accessed with an index: With
(12, 34)
it's not immediately obvious which of the two is the weight and which the value, anditem[1]
doesn't tell the reader that it accesses the value.But otherwise, frankly, I'm not convinced: The two tuples in your example can only be assigned to each other because they have the same number of fields, with the same types and names.
If I have an RGB color
tuple[r, g, b: int]
and a 3D pointtuple[x, y, z: int]
they are not interchangeable because their fields have different names.And wouldn't that argument apply to all uses of tuples, anywhere?
But I'm OK with making them objects if you think that's better. The only downside would be that the tests would need the typename for each construction of an
Item
.Creating a helper function would allow us to shorten that but wouldn't we bring back the ambiguity in return?