如何获取0-1背包中的选定物品列表?

Posted

技术标签:

【中文标题】如何获取0-1背包中的选定物品列表?【英文标题】:How to get the list of selected items in 0-1 knapsack? 【发布时间】:2018-02-10 06:22:28 【问题描述】:

我有一个背包问题的简单解决方案的代码,我想获取所选项目的索引列表,目前它正在返回所选项目的值的总和。 任何帮助将不胜感激。 JAVA代码:

/* 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));
    

当前结果:148 预期结果:2,7

【问题讨论】:

检查这个链接 - youtube.com/… 它有一个关于如何做的视频教程,我认为它比书面解决方案更容易理解 我后来注意到了,但你的解决方案是递归的,而不是 dp。所以视频中的方法对你不起作用。您可以做的是创建一个visited 数组,如果您使用的是第i 个元素,则为visited[i]=1,否则为0 @monster 看不懂能不能在代码里修改一下? 【参考方案1】:

你可以这样做(虽然它使用了一些额外的内存)-

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);
    

我所做的是我创建了一个访问过的数组,如果使用当前元素而不是我标记当前元素的访问过,否则它保持为零。最后,我遍历了这个数组并打印出每一个被访问为 1 的元素

【讨论】:

通过使用boolean 而不是int 的数组,可以在此解决方案中节省一些内存,因为 int 可以在 2 - 4 个字节之间,布尔值只有 1 个字节。与其将数组中的元素设置为 1,不如将其设置为 true 即可。 有人能用python翻译同样的代码吗【参考方案2】:

即使公认的解决方案可以满足需要,我认为它也存在一些缺陷。基本上,我们可以使用一种技巧来提高时间效率并跟踪所选项目。

背包问题可以通过动态规划来解决,这意味着我们需要缓存中间结果并使用它们来做更少的计算。请注意,接受的代码不存储中间结果,这意味着某些组合被计算多次。这在这里有很好的描述:geeksforgeeks。 回到您的问题(因为 geekforgeeks 上的文章没有说明如何恢复所选项目):

我们可以使用缓存数组来恢复选中的项目: 我们从最后一个元素开始,因为我们的缓存是二维数组,这是

var r = K.length -1
car c = K(0).length -1 
var curr = K(r)(c)

现在,虽然我们没有到达第一行(我们不检查第一行,因为它是辅助的),我们将当前值与前一行(同一列)的值进行比较。如果它们相同,这意味着我们没有使用相应的项目,所以我们只需转到 (r - 1) 行。如果它们不同 - 项目被使用,我们更新行和列。

// 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
    

我在这里找到了这种方法:cs.cmu.edu

【讨论】:

以上是关于如何获取0-1背包中的选定物品列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何实现回溯打印背包中的物品(允许重复物品)?

0-1背包问题

如何在单击角度7中的按钮时获取下拉列表的选定值和选定文本[重复]

0-1 背包问题

如何将引导模式内的下拉列表的选定值获取到php中的文本框中

动态规划中的0-1背包问题怎么去理解?要求给出具体实例和详细步骤。。。