一尘不染

0-1多维背包

algorithm

因此,我正在尝试生成一种算法,该算法将找到n个物品(在我的情况下为4个)的最佳组合,这些物品只能以最大的承重量(一次)放在背包中(0-1)。概括起来可能更有效,我想在背包中放置不超过四个独特的物品,以使它们的重量小于某个值W,同时使它们的总价值最大化。我的第一个尝试和假设是将多维背包问题的体积限制设为4,将所有物品的体积限制为1。但是我遇到了一个问题,那就是它不是0-1(意味着是否装在袋子里)。然后,我尝试使0-1(有界)背包代码具有多维性,但是我无法添加音量限制以及0-1要求。如何编码0-1多维背包问题?或如何修改代码以仅容纳V量且所有商品量均为1?该代码不必是Java,但这是我到目前为止的内容。

背包:

package hu.pj.alg;

import hu.pj.obj.Item;
import java.util.*;

public class ZeroOneKnapsack {

    protected List<Item> itemList  = new ArrayList<Item>();
    protected int maxWeight        = 0;
    protected int solutionWeight   = 0;
    protected int profit           = 0;
    protected boolean calculated   = false;

    public ZeroOneKnapsack() {}

    public ZeroOneKnapsack(int _maxWeight) {
        setMaxWeight(_maxWeight);
    }

    public ZeroOneKnapsack(List<Item> _itemList) {
        setItemList(_itemList);
    }

    public ZeroOneKnapsack(List<Item> _itemList, int _maxWeight) {
        setItemList(_itemList);
        setMaxWeight(_maxWeight);
    }

    // calculte the solution of 0-1 knapsack problem with dynamic method:
    public List<Item> calcSolution() {
        int n = itemList.size();

        setInitialStateForCalculation();
        if (n > 0  &&  maxWeight > 0) {
            List< List<Integer> > c = new ArrayList< List<Integer> >();
            List<Integer> curr = new ArrayList<Integer>();

            c.add(curr);
            for (int j = 0; j <= maxWeight; j++)
                curr.add(0);
            for (int i = 1; i <= n; i++) {
                List<Integer> prev = curr;
                c.add(curr = new ArrayList<Integer>());
                for (int j = 0; j <= maxWeight; j++) {
                    if (j > 0) {
                        int wH = itemList.get(i-1).getWeight();
                        curr.add(
                            (wH > j)
                            ?
                            prev.get(j)
                            :
                            Math.max(
                                prev.get(j),
                                itemList.get(i-1).getValue() + prev.get(j-wH)
                            )
                        );
                    } else {
                        curr.add(0);
                    }
                } // for (j...)
            } // for (i...)
            profit = curr.get(maxWeight);

            for (int i = n, j = maxWeight; i > 0  &&  j >= 0; i--) {
                int tempI   = c.get(i).get(j);
                int tempI_1 = c.get(i-1).get(j);
                if (
                    (i == 0  &&  tempI > 0)
                    ||
                    (i > 0  &&  tempI != tempI_1)
                )
                {
                    Item iH = itemList.get(i-1);
                    int  wH = iH.getWeight();
                    iH.setInKnapsack(1);
                    j -= wH;
                    solutionWeight += wH;
                }
            } // for()
            calculated = true;
        } // if()
        return itemList;
    }

    // add an item to the item list
    public void add(String name, int weight, int value) {
        if (name.equals(""))
            name = "" + (itemList.size() + 1);
        itemList.add(new Item(name, weight, value));
        setInitialStateForCalculation();
    }

    // add an item to the item list
    public void add(int weight, int value) {
        add("", weight, value); // the name will be "itemList.size() + 1"!
    }

    // remove an item from the item list
    public void remove(String name) {
        for (Iterator<Item> it = itemList.iterator(); it.hasNext(); ) {
            if (name.equals(it.next().getName())) {
                it.remove();
            }
        }
        setInitialStateForCalculation();
    }

    // remove all items from the item list
    public void removeAllItems() {
        itemList.clear();
        setInitialStateForCalculation();
    }

    public int getProfit() {
        if (!calculated)
            calcSolution();
        return profit;
    }

    public int getSolutionWeight() {return solutionWeight;}
    public boolean isCalculated() {return calculated;}
    public int getMaxWeight() {return maxWeight;}

    public void setMaxWeight(int _maxWeight) {
        maxWeight = Math.max(_maxWeight, 0);
    }

    public void setItemList(List<Item> _itemList) {
        if (_itemList != null) {
            itemList = _itemList;
            for (Item item : _itemList) {
                item.checkMembers();
            }
        }
    }

    // set the member with name "inKnapsack" by all items:
    private void setInKnapsackByAll(int inKnapsack) {
        for (Item item : itemList)
            if (inKnapsack > 0)
                item.setInKnapsack(1);
            else
                item.setInKnapsack(0);
    }

    // set the data members of class in the state of starting the calculation:
    protected void setInitialStateForCalculation() {
        setInKnapsackByAll(0);
        calculated     = false;
        profit         = 0;
        solutionWeight = 0;
    }

} // class

和项目:

package hu.pj.obj;

public class Item {

    protected String name    = "";
    protected int weight     = 0;
    protected int value      = 0;
    protected int bounding   = 1; // the maximal limit of item's pieces
    protected int inKnapsack = 0; // the pieces of item in solution

    public Item() {}

    public Item(Item item) {
        setName(item.name);
        setWeight(item.weight);
        setValue(item.value);
        setBounding(item.bounding);
    }

    public Item(int _weight, int _value) {
        setWeight(_weight);
        setValue(_value);
    }

    public Item(int _weight, int _value, int _bounding) {
        setWeight(_weight);
        setValue(_value);
        setBounding(_bounding);
    }

    public Item(String _name, int _weight, int _value) {
        setName(_name);
        setWeight(_weight);
        setValue(_value);
    }

    public Item(String _name, int _weight, int _value, int _bounding) {
        setName(_name);
        setWeight(_weight);
        setValue(_value);
        setBounding(_bounding);
    }

    public void setName(String _name) {name = _name;}
    public void setWeight(int _weight) {weight = Math.max(_weight, 0);}
    public void setValue(int _value) {value = Math.max(_value, 0);}

    public void setInKnapsack(int _inKnapsack) {
        inKnapsack = Math.min(getBounding(), Math.max(_inKnapsack, 0));
    }

    public void setBounding(int _bounding) {
        bounding = Math.max(_bounding, 0);
        if (bounding == 0)
            inKnapsack = 0;
    }

    public void checkMembers() {
        setWeight(weight);
        setValue(value);
        setBounding(bounding);
        setInKnapsack(inKnapsack);
    }

    public String getName() {return name;}
    public int getWeight() {return weight;}
    public int getValue() {return value;}
    public int getInKnapsack() {return inKnapsack;}
    public int getBounding() {return bounding;}

} // class

阅读 303

收藏
2020-07-28

共1个答案

一尘不染

这是解决二维(尺寸和体积)背包背包0-1问题的通用实现。我使用矩阵而不是列表列表,因为它容易得多。这是整个类,也是测试它的主要方法。
要添加尺寸,只需向矩阵添加新尺寸,然后添加内部循环以检查所有条件。

public class MultidimensionalKnapsack {

    /** The size of the knapsack */
    private static int size;
    /** The volume of the knapsack */
    private static int vol;

    private static class Item {
        public int value;
        public int size;
        public int volume;
        public Item(int v, int w, int vol) {
            value = v;
            size = w;
            volume = vol;
        }
    }

    // Knapsack 0/1 without repetition
    // Row: problem having only the first i items
    // Col: problem having a knapsack of size j
    // Third dimension: problem having a knapsack of volume h
    private static int[][][] dynNoRep;

    private static void noRep(Item[] items) {
        dynNoRep = new int[items.length + 1][size + 1][vol + 1];
        for(int j = 0; j <= size; j++) {
            dynNoRep[0][j][0] = 0;
        }
        for(int i = 0; i <= vol; i++) {
            dynNoRep[0][0][i] = 0;
        }
        for(int i = 0; i <= items.length; i++) {
            dynNoRep[i][0][0] = 0;
        }
        for(int i = 1; i <= items.length; i++)
            for(int j = 0; j <= size; j++) {
                for(int h = 0; h <= vol; h++) {
                    if(items[i - 1].size > j)
                        // If the item i is too big, I  can't put it and the solution is the same of the problem with i - 1 items
                        dynNoRep[i][j][h] = dynNoRep[i - 1][j][h];  
                else {
                    if(items[i - 1].volume > h)
                        // If the item i is too voluminous, I can't put it and the solution is the same of the problem with i - 1 items
                        dynNoRep[i][j][h] = dynNoRep[i - 1][j][h];
                    else {
                        // The item i could be useless and the solution is the same of the problem with i - 1 items, or it could be 
                        // useful and the solution is "(solution of knapsack of size j - item[i].size and volume h - item[i].volume) + item[i].value" 
                        dynNoRep[i][j][h] = Math.max(dynNoRep[i - 1][j][h], dynNoRep[i - 1][j - items[i - 1].size][h - items[i - 1].volume] + items[i - 1].value);
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        size = 15;
        vol = 12;
        Item[] items = {new Item(2, 4, 1), new Item(1, 5, 4), new Item(6, 3, 9), 
            new Item(3, 3, 19), new Item(7, 2, 7), new Item(1, 2, 6), new Item(2, 1, 2),
            new Item(10, 9, 12), new Item(9, 10, 2), new Item(24, 23, 11)};
        System.out.print("We have the following " + items.length + " items (value, size, volume): ");
        for(int i = 0; i < items.length; i++)
            System.out.print("(" + items[i].value + ", " + items[i].size + ", " + items[i].volume + ") ");
        System.out.println();
        System.out.println("And a knapsack of size " + size + " and volume " + vol);

        noRep(items);
        System.out.println();
        // Print the solution
        int j = size, h = vol, finalSize = 0, finalValue = 0, finalVolume = 0;
        System.out.print("Items picked (value, size, volume) for 0/1 problems without repetitions: ");
        for(int i = items.length; i > 0; i--) {
            if(dynNoRep[i][j][h] != dynNoRep[i - 1][j][h]) {
                System.out.print("(" + items[i - 1].value + ", " + items[i - 1].size + ", " + items[i - 1].volume + ") ");
                finalSize += items[i - 1].size;
                finalValue += items[i - 1].value;
                finalVolume += items[i - 1].volume;
                j -= items[i - 1].size;
                h -= items[i - 1].volume;
            }
        }
        System.out.println();
        System.out.println(" Final size: " + finalSize);
        System.out.println(" Final volume: " + finalVolume);
        System.out.println(" Final value: " + finalValue);
    }

}

2020-07-28