Skip to content
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

Implement Exercise "Knapsack" #255

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
10 changes: 9 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,15 @@
"practices": [],
"prerequisites": [],
"difficulty": 3
}
},
{
"slug": "knapsack",
"name": "Knapsack",
"uuid": "2f9877d5-eec5-4048-a868-975d028147ef",
"practices": [],
"prerequisites": [],
"difficulty": 5
}
]
},
"concepts": [
Expand Down
32 changes: 32 additions & 0 deletions exercises/practice/knapsack/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 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 pairs, `wi` and `vi`, where the first element `wi` is the weight of the *i*th item and `vi` is the value for that item.

For example:

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.
17 changes: 17 additions & 0 deletions exercises/practice/knapsack/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [],
"files": {
"solution": [
"zcl_knapsack.clas.abap"
],
"test": [
"zcl_knapsack.clas.testclasses.abap"
],
"example": [
".meta/zcl_knapsack.clas.abap"
]
},
"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"
}
64 changes: 64 additions & 0 deletions exercises/practice/knapsack/.meta/zcl_knapsack.clas.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
CLASS zcl_knapsack DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

TYPES: BEGIN OF item_type,
weight TYPE i,
value TYPE i,
END OF item_type.
TYPES items_type TYPE TABLE OF item_type.

METHODS get_max_possible_value
IMPORTING weight_limit TYPE i
items TYPE items_type
RETURNING VALUE(max_value) TYPE i.

PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.



CLASS zcl_knapsack IMPLEMENTATION.


METHOD get_max_possible_value.

TYPES int_table TYPE STANDARD TABLE OF i WITH NON-UNIQUE KEY table_line.
DATA matrix TYPE STANDARD TABLE OF int_table.

" Implementation of dynamic programming approach
" https://en.wikipedia.org/wiki/Knapsack_problem#0-1_knapsack_problem

DO lines( items ) + 1 TIMES.
APPEND VALUE #( ) TO matrix REFERENCE INTO DATA(item_line).
DO weight_limit + 1 TIMES.
APPEND VALUE #( ) TO item_line->*.
ENDDO.
ENDDO.

DATA i TYPE i VALUE 2.
DATA j TYPE i.

DO lines( items ) TIMES.
j = 1.
DO weight_limit + 1 TIMES.
" Include current item only if it yields a value increase
" Including item is only an option if current weight limit is met
matrix[ i ][ j ] = nmax( val1 = matrix[ i - 1 ][ j ]
val2 = COND i( WHEN items[ i - 1 ]-weight <= j - 1
THEN matrix[ i - 1 ][ j - items[ i - 1 ]-weight ]
+ items[ i - 1 ]-value
ELSE 0 ) ).
j += 1.
ENDDO.
i += 1.
ENDDO.

max_value = matrix[ lines( items ) + 1 ][ weight_limit + 1 ].

ENDMETHOD.
ENDCLASS.
10 changes: 10 additions & 0 deletions exercises/practice/knapsack/package.devc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_DEVC" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<DEVC>
<CTEXT>Exercism: Knapsack</CTEXT>
</DEVC>
</asx:values>
</asx:abap>
</abapGit>
31 changes: 31 additions & 0 deletions exercises/practice/knapsack/zcl_knapsack.clas.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
CLASS zcl_knapsack DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

TYPES: BEGIN OF item_type,
weight TYPE i,
value TYPE i,
END OF item_type.
TYPES items_type TYPE TABLE OF item_type.

METHODS get_max_possible_value
IMPORTING weight_limit TYPE i
items TYPE items_type
RETURNING VALUE(max_value) TYPE i.

PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.



CLASS zcl_knapsack IMPLEMENTATION.

METHOD get_max_possible_value.
" add solution here
ENDMETHOD.

ENDCLASS.
111 changes: 111 additions & 0 deletions exercises/practice/knapsack/zcl_knapsack.clas.testclasses.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
CLASS ltcl_knapsack DEFINITION FINAL FOR TESTING
DURATION SHORT
RISK LEVEL HARMLESS.

PRIVATE SECTION.

DATA cut TYPE REF TO zcl_knapsack.

METHODS setup.

METHODS no_items FOR TESTING RAISING cx_static_check.
METHODS one_item_too_heavy FOR TESTING RAISING cx_static_check.
"! five items (cannot be greedy by weight)
METHODS five_items_cannot_be_greedy_1 FOR TESTING RAISING cx_static_check.
"! five items (cannot be greedy by value)
METHODS five_items_cannot_be_greedy_2 FOR TESTING RAISING cx_static_check.
METHODS example_knapsack FOR TESTING RAISING cx_static_check.
METHODS eight_items FOR TESTING RAISING cx_static_check.
METHODS fifteen_items FOR TESTING RAISING cx_static_check.

ENDCLASS.


CLASS ltcl_knapsack IMPLEMENTATION.

METHOD setup.
cut = NEW #( ).
ENDMETHOD.

METHOD no_items.
cl_abap_unit_assert=>assert_equals(
exp = 0
act = cut->get_max_possible_value( weight_limit = 100
items = VALUE #( ) ) ).
ENDMETHOD.

METHOD one_item_too_heavy.
cl_abap_unit_assert=>assert_equals(
exp = 0
act = cut->get_max_possible_value( weight_limit = 10
items = VALUE #( ( weight = 100 value = 1 ) ) ) ).
ENDMETHOD.

METHOD five_items_cannot_be_greedy_1.
cl_abap_unit_assert=>assert_equals(
exp = 21
act = cut->get_max_possible_value( weight_limit = 10
items = VALUE #( ( weight = 2 value = 5 )
( weight = 2 value = 5 )
( weight = 2 value = 5 )
( weight = 2 value = 5 )
( weight = 10 value = 21 ) ) ) ).
ENDMETHOD.

METHOD five_items_cannot_be_greedy_2.
cl_abap_unit_assert=>assert_equals(
exp = 80
act = cut->get_max_possible_value( weight_limit = 10
items = VALUE #( ( weight = 2 value = 20 )
( weight = 2 value = 20 )
( weight = 2 value = 20 )
( weight = 2 value = 20 )
( weight = 10 value = 50 ) ) ) ).
ENDMETHOD.

METHOD example_knapsack.
cl_abap_unit_assert=>assert_equals(
exp = 90
act = cut->get_max_possible_value( weight_limit = 10
items = VALUE #( ( weight = 5 value = 10 )
( weight = 4 value = 40 )
( weight = 6 value = 30 )
( weight = 4 value = 50 ) ) ) ).
ENDMETHOD.

METHOD eight_items.
cl_abap_unit_assert=>assert_equals(
exp = 900
act = cut->get_max_possible_value( weight_limit = 104
items = VALUE #( ( 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 ) ) ) ).
ENDMETHOD.

METHOD fifteen_items.
cl_abap_unit_assert=>assert_equals(
exp = 1458
act = cut->get_max_possible_value( weight_limit = 750
items = VALUE #( ( 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 ) ) ) ).
ENDMETHOD.

ENDCLASS.
17 changes: 17 additions & 0 deletions exercises/practice/knapsack/zcl_knapsack.clas.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOCLASS>
<CLSNAME>ZCL_KNAPSACK</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>Exercism: Knapsack</DESCRIPT>
<STATE>1</STATE>
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
</VSEOCLASS>
</asx:values>
</asx:abap>
</abapGit>
Loading