Algorithm 改进的背包算法

Algorithm 改进的背包算法,algorithm,knapsack-problem,Algorithm,Knapsack Problem,我有不同种类的物品。每个项目都有值和重量 例如: ClassA:[A1、A2、A3] ClassB:[B1、B2、B3] ClassC:[C1、C2、C3] 如何修改经典0-1背包问题,使算法优化解决方案最大化总体价值,考虑类中的所有项目,但允许最多从一个类中挑选一个项目? package knapsack; import java.util.ArrayList; import java.util.List; public class Knapsack { private int

我有不同种类的物品。每个项目都有
重量

例如:

ClassA:[A1、A2、A3]

ClassB:[B1、B2、B3]

ClassC:[C1、C2、C3]

如何修改经典0-1背包问题,使算法优化解决方案最大化总体价值,考虑类中的所有项目,但允许最多从一个类中挑选一个项目?

package knapsack;

import java.util.ArrayList;
import java.util.List;

public class Knapsack {

    private int totalNumberOfItems;
    private int maxmimumKnapsackCapacityUnits;

    private double[][] optimum;
    private boolean[][] solution;

    private double [] value;
    private int [] weight;

    public Knapsack(int knapsackCapacityUnits, List<KnapsackItem> items){

        this.totalNumberOfItems = items.size();
        this.maxmimumKnapsackCapacityUnits = knapsackCapacityUnits;

        this.optimum = new double[items.size() + 1][knapsackCapacityUnits + 1];
        this.solution = new boolean[items.size() + 1][knapsackCapacityUnits + 1];

        this.value = new double[items.size() + 1];
        this.weight = new int[items.size() + 1];

        int index=1;
        for(KnapsackItem item : items){
            value[index] = item.value;
            weight[index] = item.weight;
            index++;
        }


}

public List<KnapsackItem> optimize(){

    for(int currentItem = 1; currentItem <= totalNumberOfItems; currentItem++){
        for(int currentWeightUnit = 1; currentWeightUnit <= maxmimumKnapsackCapacityUnits; currentWeightUnit++){

            double option1 = optimum[currentItem - 1][currentWeightUnit];

            double option2 = Integer.MIN_VALUE;

            if(weight[currentItem] <= currentWeightUnit){
                option2 = value[currentItem] + optimum[currentItem-1][currentWeightUnit - weight[currentItem]];
            }

            optimum[currentItem][currentWeightUnit] = Math.max(option1, option2);
            solution[currentItem][currentWeightUnit] = (option2 > option1);
        }
    }

    boolean take [] = new boolean[totalNumberOfItems + 1];
    for(int currentItem = totalNumberOfItems,
            currentWeightUnit = maxmimumKnapsackCapacityUnits; 
            currentItem > 0; currentItem --){
        if(solution[currentItem][currentWeightUnit]){
            take[currentItem] = true;
            currentWeightUnit = currentWeightUnit - weight[currentItem];
        }
        else{
            take[currentItem] = false;
        }
    }

    List<KnapsackItem> items = new ArrayList<KnapsackItem>();
    for(int i = 0; i < take.length; i++){
        KnapsackItem newItem = new KnapsackItem();
        newItem.value = value[i];
        newItem.weight = weight[i];
        newItem.isTaken = take[i];
        items.add(newItem);
    }

    return items;
}
}
包裹背包;
导入java.util.ArrayList;
导入java.util.List;
公务舱背包{
私人int totalNumberOfItems;
私有int最大背包容量;
私人双[]最优;
私有布尔[][]解决方案;
私人双[]值;
私有int[]权重;
公共背包(int背包,列表项){
this.totalNumberOfItems=items.size();
this.maxmimumKnapsackCapacityInits=背包容量Inits;
this.optimum=新的双精度[items.size()+1][背包容量yunits+1];
this.solution=new boolean[items.size()+1][knapsackCapacityUnits+1];
this.value=新的双精度[items.size()+1];
this.weight=新整数[items.size()+1];
int指数=1;
用于(背包项目:项目){
值[索引]=项值;
重量[指数]=项目重量;
索引++;
}
}
公共列表优化(){

对于(int currentItem=1;currentItem,经典算法如下:

for i in items:
    for w in possible total weights (downwards):
        if w is achievable with maximum value v:
            (w + weight[i]) is also achievable with at least value (v + value[i])
这里的方法将是一个轻微的变化:

for c in classes:
    for w in possible total weights (downwards):
        if w is achievable with maximum value v:
            for i in items of class c:
                (w + weight[i]) is also achievable with at least value (v + value[i])

对于您的代码,更改如下:

  • 也许你会想为每个类单独列出项目。按照目前的做法,我希望
    value
    weight
    成为列表列表,以及一些名为
    numberOfClasses
    numberOfClassItems
    的变量和数组来监控新列表的长度。
    例如,假设两个1类项目是(w=2,v=3)和(w=3,v=5),三个2类项目是(w=1,v=1),(w=4,v=1)和(w=1,v=4),那么我们将得到:
    totalNumberOfItems=5

    numberOfClasses=2

    numberOfClassItems=[2,3]

    value=[[3,5],[1,1,4]

    weight=[[2,3],[1,4,1]]

    也就是说,如果从
    0
    进行索引,那么从
    1
    进行索引将在每个列表的开头留下未使用的零或空列表

  • 用于(currentItem)
  • 循环将成为用于(currentClass)
    循环。数组
    最佳
    解决方案
    将由
    currentClass
    索引,而不是
    currentItem

  • 实际上,
    选项2
    的值将被计算为几个选项中的最佳选项,每个类别项目一个:
    
    double option2=整数.MIN_值;
    
    对于(CurrTeNTEM=1;CurristMe:P>),解决这个问题的方法是将类<代码> A、B、C < /代码>作为项目本身,然后在各个类中做出选择,以选择它们中最好的。
    number of items = number of classes = N
    Knapsack capacity  = W
    Let item[i][k] be kth item of ith class.
    
    问题的简单DP解决方案,对背包解决方案进行简单修改:-

    int DP[n][W+1]={0};
    
    //base condition for item = 0
    
    for(int i=0;i<=W;i++) {
    
       for(int j=0;j<item[0].size();j++) {
             if(i>=item[0][j].weight) {
                  DP[0][i] = max(DP[0][i],item[0][j].value);
             }
       }
    
    } 
    
    //Actual DP 
    
    for(int k=0;k<=W;k++) {
    
      for(int i=0;i<n;i++) {  
    
        for(int j=0;j<item[i].size();j++) {
             if(k>=item[i][j].weight) {
                  DP[i][k] = max(DP[i][k],DP[i-1][k-item[i][j].weight]+item[i][j].value);
             }
         }
    
         DP[i][k] = max(DP[i][k],DP[i-1][k]);
    
      }
    
    }
    
    print("max value : ",DP[n-1][W]); 
    
    intdp[n][W+1]={0};
    //项的基本条件=0
    
    对于(int i=0;ithanks for reply!如果我在您修改的算法版本中理解正确,您将根据最大容量检查项目的权重
    ,如果w可以通过最大值v实现:
    ,但这会发生在您迭代类项目之前。因此我不确定该如何工作。我已经包含了我的代码,所以我的算法可能是有点不同,你可以看看我做了什么。谢谢!@WildGoat:我添加了一些指针,说明这种方法会对你的代码产生什么影响。非常感谢,我正在尝试理解你的解决方案,并对我现有的代码进行更改。我会让你知道它是如何进行的。感谢你提供了如此有建设性的答案!这应该如何工作?对于starters,类中没有单一的“最佳”项。例如,一个类可能包含一个权重为3且值为5的项,另一个权重为5且值为8的项。您事先不知道哪一个“更好”当你的能力有限时,@Gassa这是一个DP,我们不是预先决定,而是从一个类中单独选择每个项目,检查结果并选择为特定子问题提供最大权重的项目。这与原始背包问题类似,但只考虑一个类中的一个或一个项目都不考虑。你能告诉我你没有从伪代码中得到什么吗对不起,我发现文本(“从类中选择最佳项”)令人困惑:它读起来就像“每个类中只有一个最佳项”.所以,我没有太多考虑代码。现在我读了代码,它似乎做了正确的事情。@Vikramhat,你对这个有什么想法吗-?谢谢。