Skip to content

Commit 41becb8

Browse files
kahgohkotp
andauthored
Add knapsack exercise (#264)
* Add knapsack exercise * Tidy up knapsack exercise * Move record to test * Make line ending consistent Co-authored-by: Victor Goff <[email protected]> * Revert "Move record to test" This reverts commit 84a0058. This is to go back to putting the record in an include file. * Add comment to include * Add instructions.append.md --------- Co-authored-by: Victor Goff <[email protected]>
1 parent e5ff828 commit 41becb8

14 files changed

+306
-0
lines changed

config.json

+8
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,14 @@
549549
"practices": [],
550550
"prerequisites": [],
551551
"difficulty": 8
552+
},
553+
{
554+
"slug": "knapsack",
555+
"name": "Knapsack",
556+
"uuid": "5b7094ea-9702-41ca-b13b-c2100cda0bdc",
557+
"practices": [],
558+
"prerequisites": [],
559+
"difficulty": 5
552560
}
553561
]
554562
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
The items are represented by [records](https://lfe.gitbooks.io/reference-guide/content/16.html), defined in `item.lfe`.
2+
Use `item-weight` to get the weight and `item-value` to get the value.
3+
4+
```
5+
;; Create an item with weight=5, value=50
6+
(set item (make-item weight 5 value 50))
7+
8+
;; Get the weight. Returns 5.
9+
(item-weight item)
10+
11+
;; Get the value. Returns 50.
12+
(item-value item)
13+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Instructions
2+
3+
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.
4+
5+
Items will be represented as a list of items.
6+
Each item will have a weight and value.
7+
All values given will be strictly positive.
8+
Bob can take only one of each item.
9+
10+
For example:
11+
12+
```text
13+
Items: [
14+
{ "weight": 5, "value": 10 },
15+
{ "weight": 4, "value": 40 },
16+
{ "weight": 6, "value": 30 },
17+
{ "weight": 4, "value": 50 }
18+
]
19+
20+
Knapsack Maximum Weight: 10
21+
```
22+
23+
For the above, the first item has weight 5 and value 10, the second item has weight 4 and value 40, and so on.
24+
In this example, Bob should take the second and fourth item to maximize his value, which, in this case, is 90.
25+
He cannot get more than 90 as his knapsack has a weight limit of 10.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Introduction
2+
3+
Bob is a thief.
4+
After months of careful planning, he finally manages to crack the security systems of a fancy store.
5+
6+
In front of him are many items, each with a value and weight.
7+
Bob would gladly take all of the items, but his knapsack can only hold so much weight.
8+
Bob has to carefully consider which items to take so that the total value of his selection is maximized.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"authors": [
3+
"kahgoh"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/knapsack.lfe"
8+
],
9+
"test": [
10+
"test/knapsack-tests.lfe"
11+
],
12+
"example": [
13+
".meta/example.lfe"
14+
],
15+
"editor": [
16+
"include/item.lfe"
17+
]
18+
},
19+
"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.",
20+
"source": "Wikipedia",
21+
"source_url": "https://en.wikipedia.org/wiki/Knapsack_problem"
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
(defmodule knapsack
2+
(export (maximum-value 2)))
3+
4+
(include-lib "include/item.lfe")
5+
6+
(defun find-max
7+
(item last-values capacity)
8+
(let*
9+
((value-without (lists:nth (+ capacity 1) last-values))
10+
(weight-value (item-weight item))
11+
(value-value (item-value item))
12+
(left-over-capacity (- capacity weight-value)))
13+
(if
14+
(< left-over-capacity 0)
15+
value-without
16+
(let
17+
((value-with
18+
(+
19+
(lists:nth (+ left-over-capacity 1) last-values)
20+
value-value)))
21+
(if (> value-with value-without) value-with value-without)))))
22+
23+
(defun next-values
24+
([item last-values -1 acc] acc)
25+
([item last-values capacity acc]
26+
(next-values
27+
item
28+
last-values
29+
(- capacity 1)
30+
(cons (find-max item last-values capacity) acc))))
31+
32+
(defun do-maximum-values
33+
(['() last-values capacity] (lists:last last-values))
34+
([(cons item remaining) last-values capacity]
35+
(do-maximum-values
36+
remaining
37+
(next-values item last-values capacity '())
38+
capacity)))
39+
40+
(defun maximum-value
41+
(('() _capacity) 0)
42+
((items capacity)
43+
(do-maximum-values
44+
items
45+
(lists:duplicate
46+
(+ capacity 1)
47+
0)
48+
capacity)))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[a4d7d2f0-ad8a-460c-86f3-88ba709d41a7]
13+
description = "no items"
14+
include = false
15+
16+
[3993a824-c20e-493d-b3c9-ee8a7753ee59]
17+
description = "no items"
18+
reimplements = "a4d7d2f0-ad8a-460c-86f3-88ba709d41a7"
19+
20+
[1d39e98c-6249-4a8b-912f-87cb12e506b0]
21+
description = "one item, too heavy"
22+
23+
[833ea310-6323-44f2-9d27-a278740ffbd8]
24+
description = "five items (cannot be greedy by weight)"
25+
26+
[277cdc52-f835-4c7d-872b-bff17bab2456]
27+
description = "five items (cannot be greedy by value)"
28+
29+
[81d8e679-442b-4f7a-8a59-7278083916c9]
30+
description = "example knapsack"
31+
32+
[f23a2449-d67c-4c26-bf3e-cde020f27ecc]
33+
description = "8 items"
34+
35+
[7c682ae9-c385-4241-a197-d2fa02c81a11]
36+
description = "15 items"

exercises/practice/knapsack/Makefile

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
ERL := $(shell which erl)
2+
REBAR3 := $(shell which rebar3)
3+
4+
null :=
5+
space := $(null) #
6+
comma := ,
7+
8+
ifeq ($(ERL),)
9+
$(error Can't find Erlang executable 'erl')
10+
else ifeq ($(REBAR3),)
11+
$(error Can't find rebar3)
12+
endif
13+
14+
compile: ; $(REBAR3) compile
15+
16+
clean: ; $(REBAR3) clean
17+
18+
.PHONY: test
19+
test:
20+
$(REBAR3) eunit \
21+
-m $(subst $(space),$(comma),$(basename $(notdir $(wildcard test/*.lfe))))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
; This include file defines the item record used in the exercise.
2+
; There shouldn't be any need to modify this file.
3+
4+
(defrecord item weight value)
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{plugins, [{rebar3_lfe, "0.4.10"}]}.
2+
3+
{provider_hooks, [{post, [{compile, {lfe, compile}}]}]}.
4+
5+
{deps, [{lfe, "2.1.3"}]}.
6+
7+
{profiles,
8+
[{test,
9+
[{eunit_compile_opts, [{src_dirs, ["src", "test"]}]},
10+
{deps,
11+
[{ltest, "0.13.8"}]}]}]}.
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{"1.2.0",
2+
[{<<"lfe">>,{pkg,<<"lfe">>,<<"2.1.3">>},0}]}.
3+
[
4+
{pkg_hash,[
5+
{<<"lfe">>, <<"6EFCB2BBC1FFC21DC5D1C092F00EFDB397EAC889474AC5C86EDF78A3557CC730">>}]},
6+
{pkg_hash_ext,[
7+
{<<"lfe">>, <<"4E4BAD515A169AE418FEB7374EA1C8D741FAEA9D95E266CE343B45BCC377F55B">>}]}
8+
].
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
%% -*- erlang -*-
2+
{application, 'knapsack',
3+
[{description, "exercism.org - knapsack"},
4+
{vsn, "0.0.1"},
5+
{modules,
6+
['knapsack']},
7+
{registered, []},
8+
{applications,
9+
[kernel, stdlib]},
10+
{included_applications, []},
11+
{env, []}]}.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
(defmodule knapsack
2+
(export (maximum-value 2)))
3+
4+
(include-lib "include/item.lfe")
5+
6+
; Please implement the exported function(s).
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
(defmodule knapsack-tests
2+
(behaviour ltest-unit)
3+
(export all))
4+
5+
(include-lib "include/item.lfe")
6+
(include-lib "ltest/include/ltest-macros.lfe")
7+
8+
(deftest no-items
9+
(is-equal 0 (knapsack:maximum-value '() 100)))
10+
11+
(deftest one-item-too-heavy
12+
(is-equal 0
13+
(knapsack:maximum-value
14+
(list
15+
(make-item weight 100 value 1))
16+
10)))
17+
18+
(deftest five-items-cannot-be-greedy-by-weight
19+
(is-equal 21
20+
(knapsack:maximum-value
21+
(list
22+
(make-item weight 2 value 5)
23+
(make-item weight 2 value 5)
24+
(make-item weight 2 value 5)
25+
(make-item weight 2 value 5)
26+
(make-item weight 10 value 21))
27+
10)))
28+
29+
(deftest five-items-cannot-be-greedy-by-value
30+
(is-equal 80
31+
(knapsack:maximum-value
32+
(list
33+
(make-item weight 2 value 20)
34+
(make-item weight 2 value 20)
35+
(make-item weight 2 value 20)
36+
(make-item weight 2 value 20)
37+
(make-item weight 10 value 50))
38+
10)))
39+
40+
(deftest example-knapsack
41+
(is-equal 90
42+
(knapsack:maximum-value
43+
(list
44+
(make-item weight 5 value 10)
45+
(make-item weight 4 value 40)
46+
(make-item weight 6 value 30)
47+
(make-item weight 4 value 50))
48+
10)))
49+
50+
(deftest 8-items
51+
(is-equal 900
52+
(knapsack:maximum-value
53+
(list
54+
(make-item weight 25 value 350)
55+
(make-item weight 35 value 400)
56+
(make-item weight 45 value 450)
57+
(make-item weight 5 value 20)
58+
(make-item weight 25 value 70)
59+
(make-item weight 3 value 8)
60+
(make-item weight 2 value 5)
61+
(make-item weight 2 value 5))
62+
104)))
63+
64+
(deftest 15-items
65+
(is-equal 1458
66+
(knapsack:maximum-value
67+
(list
68+
(make-item weight 70 value 135)
69+
(make-item weight 73 value 139)
70+
(make-item weight 77 value 149)
71+
(make-item weight 80 value 150)
72+
(make-item weight 82 value 156)
73+
(make-item weight 87 value 163)
74+
(make-item weight 90 value 173)
75+
(make-item weight 94 value 184)
76+
(make-item weight 98 value 192)
77+
(make-item weight 106 value 201)
78+
(make-item weight 110 value 210)
79+
(make-item weight 113 value 214)
80+
(make-item weight 115 value 221)
81+
(make-item weight 118 value 229)
82+
(make-item weight 120 value 240))
83+
750)))
84+

0 commit comments

Comments
 (0)