Reputation: 21
i have a code of the naive solution of the Knapsack problem, i want to get the list of index of selected items, currently it is returning the total sum of values of the selected items. Any help will be appreciated. JAVA CODE:
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
/* A Naive recursive implementation of 0-1 Knapsack problem */
class Knapsack
{
// A utility function that returns maximum of two integers
static int max(int a, int b) {
return (a > b)? a : b; }
// Returns the maximum value that can be put in a knapsack of capacity W
static int knapSack(float W, float wt[], int val[], int n)
{
// Base Case
if (n == 0 || W == 0)
return 0;
// If weight of the nth item is more than Knapsack capacity W, then
// this item cannot be included in the optimal solution
if (wt[n-1] > W)
{
return knapSack(W, wt, val, n-1);
}
// Return the maximum of two cases:
// (1) nth item included
// (2) not included
else {
return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),
knapSack(W, wt, val, n-1)
);
}
}
// Driver program to test above function
public static void main(String args[])
{
int val[] = new int[]{29,74,16,55,52,75,74,35,78};
float wt[] = new float[]{85.31f,14.55f,3.98f,26.24f,63.69f,76.25f,60.02f,93.18f,89.95f};
float W = 75f;
int n = val.length;
System.out.println(knapSack(W, wt, val, n));
}
}
current result: 148 expected result: 2,7
Upvotes: 1
Views: 7536
Reputation: 330
even though the accepted solution does what is needed, I think it has some flaws. Basically, we can use one trick to make it more time-effective and also to keep track of selected items.
The knapsack problem can be solved with dynamic programming, which means, we need to cache intermediate results and use them to do fewer computations. Please note, the accepted code does not store intermediate results, meaning some combinations are calculated more than once. This is well described here: geeksforgeeks. Going back to your question (as the article on geekforgeeks doesn't tell how to restore selected items):
we can use cache array to restore selected items: we start from the last element, since our cache is 2d array, this is
var r = K.length -1
car c = K(0).length -1
var curr = K(r)(c)
Now, while we don't reach the first row (we don't check the first row as it is auxiliary) we compare the current value to the value from the previous row (same column). If they are same, this means, we didn't use the corresponding item so we just go to (r - 1) row. If they are different - the item was used, we update both row and column.
// here I use same names as in the geekforgeeks article
// val - array of values
// K - cache for intermediate results,
// wt - array of weights
i = K.length - 1
j = W
while (i > 0) {
k = K(i)(j)
if (k != K(i - 1)(j)) {
println("selected item: val(i - 1)")
j -= wt(i - 1)
}
i -= 1
}
I found this approach here:cs.cmu.edu
Upvotes: 1
Reputation: 816
Here's how you can do it (though it uses some extra of memory)-
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
/* A Naive recursive implementation of 0-1 Knapsack problem */
class Knapsack
{
// A utility function that returns maximum of two integers
static int max(int a, int b) {
return (a > b)? a : b; }
// Returns the maximum value that can be put in a knapsack of capacity W
static int knapSack(float W, float wt[], int val[], int n,int visited[])
{
// Base Case
if (n == 0 || W == 0)
return 0;
// If weight of the nth item is more than Knapsack capacity W, then
// this item cannot be included in the optimal solution
if (wt[n-1] > W)
{
return knapSack(W, wt, val, n-1,visited);
}
// Return the maximum of two cases:
// (1) nth item included
// (2) not included
else {
int v1[]=new int[visited.length];
System.arraycopy(visited, 0, v1, 0, v1.length);
int v2[]=new int[visited.length];
System.arraycopy(visited, 0, v2, 0, v2.length);
v1[n-1]=1;
int ans1 = val[n-1] + knapSack(W-wt[n-1], wt, val, n-1,v1);
int ans2 = knapSack(W, wt, val, n-1,v2);
if(ans1>ans2){
System.arraycopy(v1, 0, visited, 0, v1.length);
return ans1;
}
else{
System.arraycopy(v2, 0, visited, 0, v2.length);
return ans2;
}
}
}
// Driver program to test above function
public static void main(String args[])
{
int val[] = new int[]{29,74,16,55,52,75,74,35,78};
float wt[] = new float[]{85.31f,14.55f,3.98f,26.24f,63.69f,76.25f,60.02f,93.18f,89.95f};
float W = 75f;
int n = val.length;
int visited[] = new int[n];
System.out.println(knapSack(W, wt, val, n, visited));
for(int i=0;i<n;i++)
if(visited[i]==1)
System.out.println(i+1);
}
}
What i did is that i created a visited array and if current element is used than i marked visited of current element one otherwise it remains zero. Finally, i iterated through this array and printed every element for which visited is 1
Upvotes: 5