简体   繁体   中英

How to get the list of selected items in 0-1 knapsack?

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM