Reputation:
So I'm looking at this code here from this website regarding the knapsack 0-1 problem.
I want to modify the program they provide so that it returns which values were selected along with the corresponding index. For example, for this situation, the solution outputs 390 but I want it to also print out the values that have been selected. So in this case, I want it to print:
Items selected :
#2 60
#3 90
#5 240
Here is what I have so far:
// A Dynamic Programming based solution for 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(int W, int wt[], int val[], int n)
{
int i, w;
int K[][] = new int[n+1][W+1];
int[] selected = new int[n + 1];
// Build table K[][] in bottom up manner
for (i = 0; i <= n; i++)
{
for (w = 0; w <= W; w++)
{
if (i==0 || w==0){
//selected[i] = 1;
K[i][w] = 0;
}
else if (wt[i-1] <= w){
selected[i] = 1;
K[i][w] = max(val[i-1] + K[i-1][w-wt[i-1]], K[i-1][w]);
}
else{
selected[i]=0;
K[i][w] = K[i-1][w];
}
}
}
System.out.println("\nItems selected : ");
for (int x = 1; x < n + 1; x++)
if (selected[x] == 1)
System.out.print(x +" ");
System.out.println();
return K[n][W];
}
// Driver program to test above function
public static void main(String args[])
{
int val[] = new int[]{300,60,90,100,240};
int wt[] = new int[]{50,10,20,40,30};
int W = 60;
int n = val.length;
System.out.println(knapSack(W, wt, val, n));
}
}
What I did was create a 1-D array of type int to mark an index true if that value was chosen. Or at least, that's what I'm trying to do.
But this is printing every index. Until I figure that part out, I won't know how to also return the corresponding weights. I know my logic in the code is wrong so can someone point me in the right direction?
Upvotes: 2
Views: 2391
Reputation: 9093
Unfortunately it's very hard to set which items are selected as you go in a dynamic programming problem. As the solution necessarily builds off of solutions to sub-problems, you'd need to store the items selected in each of those sub-solutions as well, and then aggregate this at the end.
Luckily, there's a better way. We can backtrace using the final solution and see what values we ended up using. Simply replace the section where you print your values with:
System.out.println("\nItems selected : ");
int tempW = W;
int y = 0; //to index in selected
for (int x = n; x > 0; x--){
if ((tempW-wt[x-1] >= 0) && (K[x][tempW] - K[x-1][tempW-wt[x-1]] == val[x-1]) ){
selected[y++] = x-1; //store current index and increment y
tempW-=wt[x-1];
}
}
for(int j = y-1; j >= 0; j--){
System.out.print("#" + (selected[j]+1) + " ");
System.out.println(val[selected[j]]);
}
This will print:
Items selected:
#2 60
#3 90
#5 240
390
To print the items out in ascending order, we must store them and print them in a separate for
loop. This is for the same reason we must backtrace in the first place: from the starting point there are many paths to take, while from the ending point there is only one path back to the start.
Upvotes: 1