Is there a algorithm to determine a knapsack which has an exact weight W? I.e. it's like the normal 0/1 knapsack problem with n items each having weight w_i and value v_i. Maximise the value of all the items, however the total weight of the items in the knapsack need to have exactly weight W!
I know the "normal" 0/1 knapsack algorithm but this could also return a knapsack with less weight but higher value. I want to find the highest value but exact W weight.
Here is my 0/1 knapsack implementation:
public class KnapSackTest {
public static void main(String[] args) {
int[] w = new int[] {4, 1, 5, 8, 3, 9, 2}; //weights
int[] v = new int[] {2, 12, 8, 9, 3, 4, 3}; //values
int n = w.length;
int W = 15; // W (max weight)
int[][] DP = new int[n+1][W+1];
for(int i = 1; i < n+1; i++) {
for(int j = 0; j < W+1; j++) {
if(i == 0 || j == 0) {
DP[i][j] = 0;
} else if (j - w[i-1] >= 0) {
DP[i][j] = Math.max(DP[i-1][j], DP[i-1][j - w[i-1]] + v[i-1]);
} else {
DP[i][j] = DP[i-1][j];
}
}
}
System.out.println("Result: " + DP[n][W]);
}
}
This gives me:
Result: 29
(Just ask if anything is unclear in my question!)
The most obvious solution to this problem is brute force recursive. This solution is brute-force because it evaluates the total weight and value of all possible subsets, then selects the subset with the highest value that is still under the weight limit.
The 0/1 knapsack problem means that the items are either completely or no items are filled in a knapsack. For example, we have two items having weights 2kg and 3kg, respectively. If we pick the 2kg item then we cannot pick 1kg item from the 2kg item (item is not divisible); we have to pick the 2kg item completely.
The knapsack problem is a problem in combinatorial optimization: Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible.
In this problem, we are given a set of items having different weights and values. We have to find the optimal solution considering all the given items. There are three types of knapsack problems : 0-1 Knapsack, Fractional Knapsack and Unbounded Knapsack.
Items cannot be broken and an item with weight X takes X capacity of the knapsack. We take objects ‘1’ and ‘3’. The total value we get is (30 + 60) = 90. Recommended: Please try your approach on {IDE} first, before moving on to the solution.
You get exact weight knapsack by changing only the initial dp state, not the algorithm itself. The rest stays as in your question. By simply setting DP [i] [j] = -infinity in your last else clause it will do the trick. The ides behind it is to slightly change the recursive formula definition to calculate:
Time Complexity: O (2 n ). As there are redundant subproblems. Auxiliary Space : O (1). As no extra data structure has been used for storing values. Since subproblems are evaluated again, this problem has Overlapping Sub-problems property. So the 0-1 Knapsack problem has both properties (see this and this) of a dynamic programming problem.
Approach: The traditional famous 0-1 knapsack problem can be solved in O (N*C) time but if the capacity of the knapsack is huge then a 2D N*C array can’t make be made. Luckily, it can be solved by redefining the states of the dp. Let’s have a look at the states of the DP first.
Actually, the accepted answer is wrong, as found by @Shinchan in the comments.
You get exact weight knapsack by changing only the initial dp
state, not the algorithm itself.
The initialization, instead of:
if(i == 0 || j == 0) {
DP[i][j] = 0;
}
should be:
if (j == 0) {
DP[i][j] = 0;
} else if (i == 0 && j > 0) { // obviously `&& j > 0` is not needed, but for clarity
DP[i][j] = -inf;
}
The rest stays as in your question.
By simply setting DP[i][j] = -infinity
in your last else
clause it will do the trick.
The ides behind it is to slightly change the recursive formula definition to calculate:
j
up to item i
.Now, the induction hypothesis will change, and the proof of correctness will be very similar to regular knapsack with the following modification:
DP[i][j-weight[i]] is now the maximal value that can be constructed with exactly j-weight[i]
, and you can either take item i
, giving value of DP[i][j-weight[i]]
, or not taking it, giving value of DP[i-1][j]
- which is the maximal value when using exactly weight j
with first i-1
items.
Note that if for some reason you cannot construct DP[i][j]
, you will never use it, as the value -infinity will always discarded when looking for MAX.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With