I need to modify wiki's knapsack pseudocode for my homework so it checks whether you can achieve exact weight W in the knapsack or not. Number of items is unlimited and you the value not important. I am thinking to add a while loop under j>-W[j] to check how many same items would it fit. Will that work?
Thanks
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for w from 0 to W do
m[0, w] := 0
end for
for i from 1 to n do
for j from 0 to W do
if j >= w[i] then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for
If I'm not missing anything, if you are referring to this wiki article
In the modified version, your values array shall be the same as your w array. After calculating m[n,W], simply check whether it is equal to W.
EDIT:
If you have unlimited number of items, then you are dealing with Unbounded Knapsack Problem. This is a different problem and the same article gives the dynamic programming implementation for solving it.
Related
Got this task from a game.
Farmer has
a field of constant size 16
a daily water supply which he can improve while progressing the game. For a given day it is 100, in a few days it may become 130.
around 50 types of crops. Each crop has daily yield (in gold coins) and water consumption.
Each crop type must be unique (planted once per day)
The goal is to get maximum gold per day.
Which breaks down to finding 1-16 crops whose sum of water consumption is no more than water supply (input parameter, e.g. 100) and yield sum is maximum.
Crop types are generated randomly with yield range 10-50000 and consumption range 1-120.
Brute force needs 50!/(50-16)! iterations - about 10e27.
Are there any more optimal ways to find max output?
This is called the Knapsack problem. Here's pseudocode lifted from Wikipedia.
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
// NOTE: The array "v" and array "w" are assumed to store all relevant values starting at index 1.
array m[0..n, 0..W];
for j from 0 to W do:
m[0, j] := 0
for i from 1 to n do:
m[i, 0] := 0
for i from 1 to n do:
for j from 0 to W do:
if w[i] > j then:
m[i, j] := m[i-1, j]
else:
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
https://en.wikipedia.org/wiki/Knapsack_problem
https://medium.com/#fabianterh/how-to-solve-the-knapsack-problem-with-dynamic-programming-eb88c706d3cf
Is there a way to compute the knapsack problem incrementally? Any approximation algorithm? I am trying to solve the problem in the following scenario.
Let D be my data set which is not ordered and should not be. D is divided into 3 subsets, namely D1, D2 and D3. D1, D2 and D3 can each be ordered if needed. I want to compute separate knapsack solutions for sets (D1,D2) and (D2,D3), but I don't want to avoid computing D2 two times. So, basically, I want to:
compute (D2) // do some operation
save it as an intermediate result
use it with D1 and get knapsack result for (D1, D2)
use it with D3 and get knapsack result for (D2,D3)
That way the data traversal over D2 is done only once. Is there a way to solve the knapsack incrementally like this?
Wikipedia gives this pseudocode for 0/1 Knapsack: https://en.wikipedia.org/wiki/Knapsack_problem#0.2F1_knapsack_problem
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for j from 0 to W do:
m[0, j] := 0
for i from 1 to n do:
for j from 0 to W do:
if w[i-1] > j then:
m[i, j] := m[i-1, j]
else:
m[i, j] := max(m[i-1, j], m[i-1, j-w[i-1]] + v[i-1])
This builds a 2 dimensional array such that m[n, W] (the last element in the last row) is the solution -- you run this on D2.
Then you write another algorithm that takes this array as input and
Does not do the for j ... part to initialize the array
Does for i from D2.count+1 to (D2.count + other.count) do: to start where the other one left off. (you have to adjust i when looking up in the w and v arrays)
I'm working on a program to solve a variant of the 0/1 Knapsack problem.
The original problem is described here: https://en.wikipedia.org/wiki/Knapsack_problem.
In case the link goes missing in the future, I will give you a summary of the 0/1 Knapsack problem (if you are familiar with it, jump this paragraph):
Let's say we have n items, each with weight wi and value vi. We want to put items in a bag, that supports a maximum weight W, so that the total value inside the bag is the maximum possible without overweighting the bag. Items cannot have multiple instances (i.e., we only have one of each). The objective of the problem is to maximize SUM(vi.xi) so that SUM(wi.xi) <= W and xi = 0, 1 (xi represents the state of an item being or not in the bag).
For my case, there are small differences in both conditions and objective:
The weight of all items is 1, wi = 1, i = 1...n
I always want to put exactly half the items in the bag. So, the maximum weight capacity of the bag is half (rounded up) of the number of items.W = ceil[n/2] or W = floor[(n+1)/2].
Also, the weight inside the bag must be equal to its maximum capacity SUM(wi.xi) = W
Finally, instead of maximizing the value of the items inside the bag, the objective is that the value of the items inside is as close as possible to the value of the items outside. Hence, my objective is to minimize |SUM(vi.-xi) - SUM[vi(1-xi)]|, which simplifies into something like minimize |SUM[vi(2xi - 1)]|.
Now, there is a pseudo-code for the original 0/1 Knapsack problem in the Wikipedia page above (you can find it on the bottom of this text), but I am having trouble adapting it to my scenario. Can someone help? (I am not asking for code, just for an idea, so language is irrelevant)
Thanks!
Wikipedia's pseudo-code for 0/1 Knapsack problem:
Assume w1, w2, ..., wn, W are strictly positive integers. Define
m[i,w] to be the maximum value that can be attained with weight less
than or equal to w using items up to i (first i items).
We can define m[i,w] recursively as follows:
m[0, w]=0
m[i, w] = m[i-1, w] if wi > w (the new item is more than the current weight limit)
m[i, w]= max(m[i-1, w], m[i-1, w-wi] + vi) if wi <= w.
The solution can then be found by calculating m[n,W].
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for j from 0 to W do:
m[0, j] := 0
for i from 1 to n do:
for j from 0 to W do:
if w[i-1] <= j then:
m[i, j] := max(m[i-1, j], m[i-1, j-w[i-1]] + v[i-1])
else:
m[i, j] := m[i-1, j]
Thanks to #harold, it seems like this problem is not a Knapsack problem, but a Partition problem. Part of the pseudo-code I was seeking is in the corresponding Wikipedia page: https://en.wikipedia.org/wiki/Partition_problem
EDIT: well, actually, Partition problem algorithms tell you whether a Set of items can be partitioned in 2 sets of equal value or not. Suppose it can't, you have approximation algorithms, which say whether you can have the set partiotioned in 2 sets with the difference their values being lower than d.
BUT, they don't tell you the resulting sub-sets, and that's what I was seeking.
I ended up finding a question here asking for that (here: Balanced partition), with a code example which I have tested and works fine.
In http://en.wikipedia.org/wiki/Knapsack_problem, the DP is:
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for j from 0 to W do
m[0, j] := 0
end for
for i from 1 to n do
for j from 0 to W do
if w[i] <= j then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for
I think switching the order for the weight loop and the number loop does not impact the optimal solution. Is this right? Say
for j from 0 to W do
for i from 1 to n do
Thanks.
You are correct. The value of m[i,j] depends only on values with both smaller is and js. The situation where changing the lop order matters is when one of the elements can increase. For example, if m[2,2] depends on m[1,3] then we need calculate the first row comlpetely before moving to the second row.
I was reading wikipedia regarding the 0-1 knapsack problem. I just want to clarify a couple things. I have two questions:
http://en.wikipedia.org/wiki/Knapsack_problem#0.2F1_Knapsack_Problem
I encountered this pseudo-code:
// Input:
// Values (stored in array v)
// Weights (stored in array w)
// Number of distinct items (n)
// Knapsack capacity (W)
for w from 0 to W do
m[0, w] := 0
end for
for i from 1 to n do
for j from 0 to W do
if j >= w[i] then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
else
m[i, j] := m[i-1, j]
end if
end for
end for
Specifically for this part:
if j >= w[i] then
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i])
1) Correct me if I'm wrong, but shouldn't it be:
m[i, j] := max(m[i-1, j], m[i-1, j-w[i]] + v[i], m[i,j-w[i]] + v[i])
?
Or if not, can someone explain me why it's not needed?
...
2) And I also have another question, if say I want to optimize this a bit. Would it be wise to have the loop "for j from 0 to W" increment by the GCD of all the weights of the items (i.e. GCD of the values stored in array w). (I'm thinking just code-wise right now when I'm about to implement it).
1) When you add m[i,j-w[i]] + v[i], you're allowing the same item i to be selected more than once, thus it is no longer 0/1 Knapsack - it becomes a Knapsack problem with unlimited amounts of each item.
2) Yes, but this GCD usually comes down to 1 on real instances, thus not worth bothering with for general cases, unless you know beforehand that your data would benefit from it. (In this case, you'd actually want to divide all your data by the GCD, and keep the original algorithm incrementing 1 at a time, then multiply the final result by the GCD. This would save you memory as well, but your Knapsack capacity must also be divisible by such GCD)