动态规划求解01背包问题

有n个物品,每个都具有价值(记作v)和重量(记作w)两个属性。现有一个背包,最多只能装总重量为W的物品。要从这n个物品中选择若干个放入背包,使得背包中所有物品的总价值最大。(这里假设每个物品的重量w都是整数)。

 

此问题可以用动态规划求解。设n个物品的价值分别是v1,v2,……vn,重量分别是w1,w2,……,wn

 

考虑如下的问题:从n个物品中的前k个物品(下标分别是1,2,……k)中选取若干个放在容积为W的背包中,使得背包中所有物品的总价值最大。将此最大价值记为C(W, k)。

 最优子结构如下:从C(W, k)的最优方案中去掉任意一个物品(假设此物品的下标为i,重量为wi,)。那么剩下的物品刚好是从1,2,……,i-1,i+1,……k等k-1个物品中选取若干个放在容积为W-wi的背包中,使得背包中所有物品的总价值最大的方案。(使用cut and paste的方式易证)

 

递推式如下:

若C(W, k)的最优方案中包含了第k个物品,那么C(W, k) = C(W-wk, k - 1) + vk。注意,这里用到了刚刚提到的最优子结构。

若C(W, k)的方案中不包含第k个物品,那么C(W, k) = C(W, k - 1)

所以,C(W, k)为上述两种情况中的较大者:

C(W, k) = max(C(W-wk, k - 1) + vk, C(W, k - 1))

 

容易看出,重叠子问题有很多。

下面举个例子。背包最大容量是12,一共有6个物品,物品的价值和重量见下表:

编号

1

2

3

4

5

6

价值

33

34

37

32

31

39

重量

5

7

7

1

8

4

 

用一个辅助表来计算C(W, k)。

下表中,65(1,4)表示选取1号和4号物品,总价值是65。

 

物品k:1

2

3

4

5

6

容量w:0

0

0

0

0

0

0

1

0

0

0

32(4)

32(4)

32(1)

2

0

0

0

32(4)

32(4)

32(1)

3

0

0

0

32(4)

32(4)

32(1)

4

0

0

0

32(4)

32(4)

39(6)

5

33(1)

33(1)

33(1)

33(1)

33(1)

39(6)

6

33(1)

33(1)

33(1)

65(1,4)

65(1,4)

65(1,4)

7

33(1)

34(2)

37(3)

65(1,4)

65(1,4)

65(1,4)

8

33(1)

34(2)

37(3)

69(3,4)

69(3,4)

69(3,4)

9

33(1)

34(2)

37(3)

69(3,4)

69(3,4)

72(1,6)

10

33(1)

34(2)

37(3)

69(3,4)

69(3,4)

104(1,4,6)

11

33(1)

34(2)

37(3)

69(3,4)

69(3,4)

104(1,4,6)

12

33(1)

67(1,2)

70(1,3)

70(1,3)

70(1,3)

108(3,4,6)

 

 

代码如下:

 

  1 import java.util.HashSet;
  2 import java.util.Set;
  3 
  4 public class Main {
  5     
  6     private static int W = 12;
  7     
  8     private static class Solution {
  9         public Solution() {
 10             value = -1;
 11             items = new HashSet<Integer>();
 12         }
 13         
 14         private int value;
 15         private Set<Integer> items;
 16         
 17         public void setValue(int value) {
 18             this.value = value;
 19         }
 20         
 21         public int getValue() {
 22             return value;
 23         }
 24         
 25         public void addToItem(Integer n) {
 26             items.add(n);
 27         }
 28         public void addToItem(Set<Integer> set) {
 29             items.addAll(set);
 30         }
 31         
 32         public Set<Integer> getItems() {
 33             return items;
 34         }
 35     };
 36     
 37     private static int getValue(int index) {
 38         int[] value = {33, 34, 37, 32, 31, 39};
 39         
 40         return value[index - 1];
 41     }
 42     
 43     private static int getWeight(int index) {
 44         int[] weight = {5, 7, 7, 1, 8, 4};
 45         
 46         return weight[index - 1];
 47     }
 48     
 49     private static void printSolution(Solution[][] arraySolution) {
 50         for (int i = 0; i < arraySolution.length; ++i) {
 51             String s = "";
 52             for (int j = 0; j < arraySolution[i].length; ++j) {
 53                 s += String.valueOf(arraySolution[i][j].getValue()) + arraySolution[i][j].getItems() + "\t";
 54             }
 55             
 56             System.out.println(s);
 57         }
 58     }
 59     
 60     private static void calc(Solution[][] arraySolution, int i, int j) {
 61         arraySolution[i][j] = new Solution();
 62         if ((0 == i) || (0 == j))
 63         {
 64             arraySolution[i][j].setValue(0);
 65         } else {
 66             int nValue;
 67             int nWithoutCurrItem = arraySolution[i][j - 1].getValue();
 68             
 69             int nCurrWeight = getWeight(j);
 70             if (nCurrWeight > i) {
 71                 nValue = nWithoutCurrItem;
 72                 arraySolution[i][j].addToItem(arraySolution[i][j - 1].getItems());
 73             } else {
 74                 int nCurrValue = getValue(j);
 75                 int nWithCurrItem = arraySolution[i - nCurrWeight][j - 1].getValue() + nCurrValue;
 76                 
 77                 if (nWithoutCurrItem > nWithCurrItem) {
 78                     nValue = nWithoutCurrItem;
 79                     arraySolution[i][j].addToItem(arraySolution[i][j - 1].getItems());
 80                 } else {
 81                     nValue = nWithCurrItem;
 82                     arraySolution[i][j].addToItem(arraySolution[i - nCurrWeight][j - 1].getItems());
 83                     arraySolution[i][j].addToItem(j);
 84                 }
 85             }
 86             
 87             arraySolution[i][j].setValue(nValue);
 88         }
 89     }
 90     
 91     private static void calc(Solution[][] arraySolution) {
 92         for (int i = 0; i < arraySolution.length; ++i) {
 93             for (int j = 0; j < arraySolution[i].length; ++j) {
 94                 calc(arraySolution, i, j);
 95             }
 96         }
 97     }
 98 
 99     public static void main(String[] args) {
100         Solution arraySolution[][] = new Solution[W + 1][7];
101         
102         calc(arraySolution);
103         
104         printSolution(arraySolution);
105     }
106 
107 }

猜你喜欢

转载自www.cnblogs.com/adgjl/p/10424312.html