动态规划-01背包问题
2012-08-02 19:05 coodoing 阅读(1329) 评论(0) 收藏 举报1、问题描述
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大。在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包或不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。因此,该问题称为0-1背包问题。
2、算法分析
0-1背包问题的最优子结构,设(y1,y2,...,yn)是所给0-1背包问题的一个最优解,则(y2,y3,...,yn)是经过一次选择后的0-1背包问题的最优解。0-1背包问题的递归关系,设当前子问题的最优值为p[i][j],即p[i][j]表示前i个物品能装入载重量为j的背包中的最大价值。由0-1背包问题的最优子结构性质,可以建立计算p[i][j]的递归式:
若w[i]>j,第i个物品不装入背包;
否则,若w[i]<=j且第i个物品装入背包后的价值>p[i-1][j],则记录当前最大价值(替换为第i个物品装入背包后的价值)。
计算最大价值的动态规划算法:
1: for (i = 1; i < weight.length; i++) {
2: for (j = 1; j < max+1; j++) {
3: //weight[i]>j,第i个物品不装入背包
4: p[i][j] = p[i - 1][j];
5: //weight[i]<=j,且第i个物品装入背包后的价值>value[i-1][j],则记录当前最大价值
6: int temp;
7: if(j >=weight[i])
8: {
9: temp = p[i - 1][j - weight[i]] + value[i];
10: if (temp > p[i][j])
11: p[i][j] = temp;
12: }
13: }
14: }
即该段程序完成以下n个阶段:
1:只装入1个物品,确定在各种不同载重量的背包下,能够得到的最大价值;
2:装入2个物品,确定在各种不同载重量的背包下,能够得到的最大价值;
。。。
n:以此类推,装入n个物品,确定在各种不同载重量的背包下,能够得到的最大价值。
确定装入背包的具体物品,从p[n][max]向前逆推:
若p[n][max]>p[n-1][max],则第n个物品被装入背包,且前n-1个物品被装入载重量为max-w[n]的背包中
否则,第n个物品没有装入背包,且前n-1个物品被装入载重量为max的背包中
以此类推,直到确定第一个物品是否被装入背包为止。逆推代码如下:
1: for (int i = len-1; i >0; i--) {
2: if(p[i-1][temp]<p[i][temp])
3: {
4: selection[i] = true;
5: temp-=weight[i];
6: }
7: }
3、算法实现
1: public class DP_Knapsack01 {
2:
3: int[] weight;
4: int[] value;
5: int max;
6:
7: int[][] p;
8:
9: boolean[] selection ; //背包是否被选择
10:
11: public DP_Knapsack01() {
12: weight = new int[] {0, 16, 15, 15 };
13: value = new int[] {0, 45, 25, 25 };
14: max = 30;
15: selection = new boolean[weight.length];
16:
17: init();
18: }
19:
20: private void init() {
21: int row = weight.length;
22: int col = max+1 ;
23: int i, j;
24:
25: p = new int[row][col];
26: //初始化第0列
27: for(i=0;i<row;i++)
28: p[i][0]=0;
29:
30: // 表示初始时刻没装入物品时,最大价值为0
31: for(j=0;j<col;j++)
32: p[0][j]=0;
33:
34: }
35:
36: /*
37: * DP:选择与否的最优子结构性质
38: * p[i][j]表示前i个物品能装入载重量为j的背包中的最大价值
39: * p[i][j] = max{p[i-1][j],value[i]+p[i-1][j-weight[i]]}
40: * */
41: /*
42: * 该段程序完成以下n个阶段:
43: 1:只装入1个物品,确定在各种不同载重量的背包下,能够得到的最大价值
44: 2:装入2个物品,确定在各种不同载重量的背包下,能够得到的最大价值
45: 。。。
46: n:以此类推,装入n个物品,确定在各种不同载重量的背包下,能够得到的最大价值
47: * */
48: private void knapsack() {
49: int i, j;
50: for (i = 1; i < weight.length; i++) {
51: for (j = 1; j < max+1; j++) {
52: //weight[i]>j,第i个物品不装入背包
53: p[i][j] = p[i - 1][j];
54: //weight[i]<=j,且第i个物品装入背包后的价值>value[i-1][j],则记录当前最大价值
55: int temp;
56: if(j >=weight[i])
57: {
58: temp = p[i - 1][j - weight[i]] + value[i];
59: if (temp > p[i][j])
60: p[i][j] = temp;
61: }
62: }
63: }
64: }
65:
66: /* 求装入的物品
67: * 递推从value[n][max]向前逆推。
68: * 若p[n][max]>p[n-1][max],则第n个物品被装入背包,且前n-1个物品
69: * 被装入载重量为max-weight[n]的背包中。
70: 否则,第n个物品没有装入背包,且前n-1个物品被装入载重量为max的背包中。
71: * */
72: private void traceback()
73: {
74: int temp = max;
75: int len = weight.length;
76: for (int i = len-1; i >0; i--) {
77: if(p[i-1][temp]<p[i][temp])
78: {
79: selection[i] = true;
80: temp-=weight[i];
81: }
82: }
83: }
84:
85: /**
86: * @param args
87: */
88: public static void main(String[] args) {
89: // TODO Auto-generated method stub
90:
91: DP_Knapsack01 knap = new DP_Knapsack01();
92: knap.knapsack();
93:
94: knap.traceback();
95: int len = knap.weight.length;
96:
97: System.out.println("动态规划对应的value值分别为:");
98: for(int i= 0;i<len;i++)
99: {
100: if(knap.selection[i])
101: System.out.print(knap.value[i]+" ");
102: }
103: System.out.println();
104: System.out.println("动态规划对应的weight值分别为:");
105: for(int i= 0;i<len;i++)
106: {
107: if(knap.selection[i])
108: System.out.print(knap.weight[i]+" ");
109: }
110: }
111:
112: }
参考资料:
http://blog.csdn.net/livelylittlefish/article/details/2186206
浙公网安备 33010602011771号