Skip to content

Commit 8d1edbd

Browse files
committed
Added 0/1 Knapsack implementation
Both implementations now returns the maximum profit Added comments Updated tests
1 parent df435a5 commit 8d1edbd

2 files changed

Lines changed: 80 additions & 8 deletions

File tree

Knapsack/Lua/Yonaba/knapsack.lua

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,88 @@ end
1515
-- ...
1616
-- }
1717
-- In the returned output, each item will receive a new attribute 'p'
18-
-- referring to how much (percentage) of the item has been added into
18+
-- referring to how much (percentage) of the item has been added into
1919
-- the knapsack.
2020

2121
-- Performs fractional Knapsack. Fractional here means we can
2222
-- select a portion of a item. With that respect, this implementation
2323
-- is greedy.
24-
-- items : an array of items (this array will be sorted regarding
25-
-- their benefits in decreasing order)
24+
-- items : an array of items (see note before). This array will be
25+
-- sorted regarding their benefits in decreasing order.
2626
-- capacity: the maximum capacity of the knapsack
27-
-- returns : an array of items
27+
-- returns : 1. an array of items
28+
-- 2. the maximum profit
2829
local function fractionalKnapsack(items, capacity)
2930
table.sort(items, function(a, b) return a.b > b.b end)
30-
local inKnapsack = {}
31+
local inKnapsack, profit = {}, 0
3132
while capacity > 0 do
3233
local max_item = pop(items)
3334
max_item.p = max_item.w > capacity and capacity/max_item.w or 1
3435
max_item.b = max_item.p * max_item.b
3536
max_item.w = max_item.p * max_item.w
3637
capacity = capacity - max_item.w
3738
table.insert(inKnapsack, max_item)
39+
profit = profit + max_item.b
3840
end
39-
return inKnapsack
41+
return inKnapsack, profit
42+
end
43+
44+
45+
-- Performs standard 0/1 Knapsack, meaning that an item is either
46+
-- picked or not. This implementation uses dynamic programming.
47+
-- items : an array of items (see note before).
48+
-- capacity: the maximum capacity of the knapsack
49+
-- returns : 1. an array of items
50+
-- 2. the maximum profit
51+
local function integerKnapsack(items, capacity
52+
-- Get the count of items
53+
local numOfItems = #items
54+
55+
-- Auxiliary tables for dynamic search and selected items tracking
56+
local V, K = {}, {}
57+
58+
-- Inits auxiliary tables with 0's. Note that although
59+
-- Lua's arrays start at 1, we start looping at 0
60+
for i = 0, numOfItems do
61+
V[i], K[i] = {}, {}
62+
for w = 0, capacity do
63+
V[i][w], K[i][w] = 0, 0
64+
end
65+
end
66+
67+
-- Dynamic search
68+
for i = 1, numOfItems do
69+
local item = items[i]
70+
for w = 0, capacity do
71+
if item.w < w
72+
and (item.b + V[i - 1][w - item.w] > V[i - 1][w]) then
73+
V[i][w] = item.b + V[i-1][w - item.w]
74+
K[i][w] = 1
75+
else
76+
V[i][w] = V[i - 1][w]
77+
K[i][w] = 0
78+
end
79+
end
80+
end
81+
82+
-- Process auxiliary tables to identify
83+
-- selected items and evaluate the profit
84+
local inKnapsack, profit = {}, 0
85+
for i = numOfItems, 1, -1 do
86+
local item = items[i]
87+
if K[i][capacity] == 1 then
88+
table.insert(inKnapsack, item)
89+
capacity = capacity - item.w
90+
profit = profit + item.b
91+
end
92+
end
93+
94+
return inKnapsack, profit
4095
end
4196

4297
return {
4398
fractional = fractionalKnapsack,
99+
integer = integerKnapsack
44100
}
45101

46102

Knapsack/Lua/Yonaba/knapsack_test.lua

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,31 @@ run('Testing fractional knapsack', function()
2929
{name = 'Rice', w = 5, b = 6},
3030
}
3131
local capacity = 10
32-
local sack = knapsack.fractional(items, capacity)
32+
local sack, profit = knapsack.fractional(items, capacity)
3333
assert(#sack == 3)
3434
local s1, s2, s3 = sack[1], sack[2], sack[3]
35-
print('s3', s3.w-1)
3635
assert(s1.name == 'Rice' and s1.p == 1 and s1.w == 5 and s1.b == 6)
3736
assert(s2.name == 'Orange' and s2.p == 1 and s2.w == 4 and s2.b == 5)
3837
assert(s3.name == 'Apple' and fuzzyEq(s3.p,0.33) and s3.w == 1 and fuzzyEq(s3.b,1.67))
38+
print(profit)
39+
assert(fuzzyEq(profit, 12.67))
3940
end)
4041

42+
run('Testing integer knapsack', function()
43+
local items = {
44+
{name = 'Apple', w = 5, b = 10},
45+
{name = 'Orange', w = 4, b = 40},
46+
{name = 'Salt', w = 6, b = 30},
47+
{name = 'Pepper', w = 3, b = 50},
48+
}
49+
local capacity= 10
50+
local sack, profit = knapsack.integer(items, capacity)
51+
assert(#sack == 2)
52+
local s1, s2 = sack[1], sack[2]
53+
assert(s1.name == 'Pepper' and s1.w == 3 and s1.b == 50)
54+
assert(s2.name == 'Orange' and s2.w == 4 and s2.b == 40)
55+
assert(profit == 90)
56+
end)
4157

4258
print(('-'):rep(80))
4359
print(('Total : %02d: Pass: %02d - Failed : %02d - Success: %.2f %%')

0 commit comments

Comments
 (0)