2013-01-19 73 views
3

所以我試圖產生一個算法,它會找到最好的組合n項(在我的情況4),只能放在揹包一次(0-1)與最大重量容量。總結可能更有效,我想在我的揹包中放置不超過四個獨特的物品,以便它們的權重小於某個值W,同時最大化它們的總價值。我的第一次嘗試和假設是將多維揹包問題中所有項目的體積限制設爲1。但我遇到了不是0-1的問題(無論是否在袋內)。然後,我嘗試製作一個0-1(有界)揹包代碼多維,但我無法添加音量限制以及0-1要求。我如何編碼0-1多維揹包問題?或者,如何調整代碼以僅將所有項目卷的V值保持爲1?代碼不一定是Java,但這是我迄今爲止。0-1多維揹包

揹包:

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 

回答

5

這裏是一個通用的實施2點的尺寸(大小和體積),以解決該揹包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); 
    } 

}