最优解
问题描述
n n n个物品,它们有各自的重量和价值,现有给定承重量的背包,如何让背包里物品价值总和最大?
e
g
:
eg:
eg:
背包容量:
W
=
8
W=8
W=8
i i i(物品编号) | w i w_{i} wi(重量) | v i v_{i} vi(价值) |
---|---|---|
1 | 2 | 3 |
2 | 3 | 5 |
3 | 4 | 4 |
4 | 5 | 7 |
定义:
v
i
v_{i}
vi——第
i
i
i个物品的价值;
w
i
w_{i}
wi——第
i
i
i个物品的重量;
V
(
i
,
j
)
V(i,j)
V(i,j)——当前背包容量
j
j
j,前
i
i
i个物品最佳组合对应的价值。
动态规划递推式
1、边界条件,包容量或者物品数量为0,即 i = 0 o r j = 0 i=0orj=0 i=0orj=0
V ( i , 0 ) = V ( 0 , j ) = 0 V(i,0)=V(0,j)=0 V(i,0)=V(0,j)=0
2、递推条件1,包的容量比商品 i i i小,即` ( j < w i ) (j<w_i) (j<wi), i i i无法装入,此时的价值与前 i − 1 i-1 i−1个的价值是一样的;
V ( i , j ) = V ( i − 1 , j ) V(i,j)=V(i-1,j) V(i,j)=V(i−1,j)
3、递推条件2,包的容量比商品 i i i小,即 ( j ≥ w i ) (j{\ge}w_i) (j≥wi), i i i可以放入,此时选择放 i i i还是不放 i i i
- (1)
i
i
i物品不放入:
V ( i , j ) = V ( i − 1 , j ) V(i,j)=V(i-1,j) V(i,j)=V(i−1,j) - (2)
i
i
i物品放入:
V ( i , j ) = V ( i − 1 , j i ) + v i V(i,j)=V(i-1,j_i)+v_i V(i,j)=V(i−1,ji)+vi
V ( i , j ) = m a x { V ( i − 1 , j ) , V ( i − 1 , j − w i ) + v i } V(i,j)=max\{V(i-1,j),V(i-1,j-w_i)+v_i\} V(i,j)=max{V(i−1,j),V(i−1,j−wi)+vi}
填表
1、初始条件, V ( i , 0 ) = V ( 0 , j ) = 0 V(i,0)=V(0,j)=0 V(i,0)=V(0,j)=0
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | ||||||||
2 | 0 | ||||||||
3 | 0 | ||||||||
4 | 0 |
2、按递推条件
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | 0 | 0 | 3 | 5 | 5 | 8 | 8 | 8 | 8 |
3 | 0 | 0 | 3 | 5 | 5 | 8 | 8 | 9 | 9 |
4 | 0 | 0 | 3 | 5 | 5 | 8 | 8 | 10 | 12 |
- i = 1 , j = 1 , w 1 = 2 , v 1 = 3 , 有 j < w ( 1 ) , 故 V ( 1 , 1 ) = V ( 0 , 1 ) = 0 ; i=1,j=1,w_1=2,v_1=3,有j<w(1),故V(1,1)=V(0,1)=0; i=1,j=1,w1=2,v1=3,有j<w(1),故V(1,1)=V(0,1)=0;
- i = 1 , j = 2 , w 1 = 2 , v 1 = 3 , 有 j = w ( 1 ) , 故 V ( 1 , 2 ) = m a x { V ( 0 , 2 ) , V ( 0 , 2 − w 1 ) + v 1 } = m a x { V ( 0 , 2 ) , V ( 0 , 0 ) + v 1 } = m a x { 0 , 3 } = 3 ; i=1,j=2,w_1=2,v_1=3,有j=w(1),故V(1,2)=max\{V(0,2),V(0,2-w_1)+v_1\}=max\{V(0,2),V(0,0)+v_1\}=max\{0,3\}=3; i=1,j=2,w1=2,v1=3,有j=w(1),故V(1,2)=max{V(0,2),V(0,2−w1)+v1}=max{V(0,2),V(0,0)+v1}=max{0,3}=3;
- . . . ... ...
- i = 4 , j = 8 , w 1 = 5 , v 1 = 7 , 有 j > w ( 1 ) , 故 V ( 4 , 8 ) = m a x { V ( 3 , 8 ) , V ( 3 , 8 − w 1 ) + v 1 } = m a x { V ( 3 , 8 ) , V ( 3 , 3 ) + v 1 } = m a x { 9 , 10 } = 10 i=4,j=8,w_1=5,v_1=7,有j>w(1),故V(4,8)=max\{V(3,8),V(3,8-w_1)+v_1\}=max\{V(3,8),V(3,3)+v_1\}=max\{9,10\}=10 i=4,j=8,w1=5,v1=7,有j>w(1),故V(4,8)=max{V(3,8),V(3,8−w1)+v1}=max{V(3,8),V(3,3)+v1}=max{9,10}=10
代码实现
int **dp = new int*[num];
for (int i = 0; i < num ; ++i) {
dp[i] = new int[W + 1];
}
for (int i = 0; i < num; ++i) {
for (int j = 0; j < W + 1; ++j) {
dp[i][j] = 0; //必须先分配初值
}
}
for (int i = 1; i < num; ++i) {
for (int j = 1; j < W + 1; ++j) {
if (w[i] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max( dp[i - 1][j],dp[i - 1][j - w[i]] + v[i] );
}
}
return dp;
};
最优解回溯
回溯方式
1、
V
(
i
,
j
)
=
V
(
i
−
1
,
j
)
V(i,j)=V(i-1,j)
V(i,j)=V(i−1,j)时,说明没有选择第
i
i
i个商品,则返回到
V
(
i
−
1
,
j
)
V(i-1,j)
V(i−1,j);
2、
V
(
i
,
j
)
=
V
(
i
−
1
,
j
−
w
i
)
+
v
i
V(i,j)=V(i-1,j-w_i)+v_i
V(i,j)=V(i−1,j−wi)+vi,说明选择了第
i
i
i个商品,该商品是最优解组成的一部分,返回到
V
(
i
−
1
,
j
−
w
i
)
V(i-1,j-w_i)
V(i−1,j−wi);
3、
i
=
0
i=0
i=0时结束。
代码
void findWhat(int** &dp, int w[], int v[], int i, int j) {
if (i > 0) {
if (dp[i][j] == dp[i - 1][j]) {
findWhat(dp, w, v, i - 1, j);
}
else if(j>=w[i]&&dp[i][j]==dp[i-1][j-w[i]]+v[i]){
cout << i << " ";
findWhat(dp, w, v, i - 1, j - w[i]);
}
}
}