改进的背包算法

我有不同类别的项目.每个项目都有价值和重量.

例如:

A级:[A1,A2,A3]

B类:[B1,B2,B3]

C级:[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;
}
}

谢谢!

最佳答案 经典算法如下:

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

使用您的代码,更改将如下所示:

>也许你会想为每个班级单独列出一个项目.与当前所做的一致,我希望值和权重成为列表列表,以及一些名为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]]和
重量= [[2,3],[1,4,1]].
也就是说,如果您从0开始索引,那么从1开始索引将在每个列表的开头留下未使用的零或空列表.
> for(currentItem)循环将成为for(currentClass)循环.数组最优和解决方案将由currentClass而不是currentItem索引.
>值option2实际上将被计算为几个选项中的最佳选项,每个类项目一个:

double option2 = Integer.MIN_VALUE;
for(currentItem = 1; currentItem< = numberOfClassItems [currentClass];
     currentItem){
    if(weight [currentClass] [currentItem]< = currentWeightUnit){
        option2 = Math.max(option2,value [currentClass] [currentItem]
                  最佳[currentClass – 1] [currentWeightUnit –
                                            重量[currentClass] [CURRENTITEM]]);
    }
}

>也许解决方案数组现在应该包含int而不是boolean:我们采用的这个类的项目数,或者如果我们选择option1并且不使用此类的任何项目,则使用一些sentinel值(0或-1).

点赞