用d(i,j)表示当前在第i层,背包剩余容量为j时接下来的最大重量和
一共有n个物品,i不代表已经选取的物品数量,而是遍历过的物品数量
d
(
i
,
j
)
d(i,j)
d(i,j)代表剩余背包重量为j时,正在对物品i进行选取时,当前情况所可能达到的最大权重;
d
(
i
.
j
)
=
m
a
x
(
d
(
i
+
1
,
j
)
,
d
(
i
+
1
,
j
−
w
[
i
]
)
+
v
[
i
]
)
)
d(i.j)=max(d(i+1,j),d(i+1,j-w[i])+v[i]))
d(i.j)=max(d(i+1,j),d(i+1,j−w[i])+v[i]))
从决策过程的转移来看:
d
(
i
+
1
,
j
)
d(i+1,j)
d(i+1,j)代表我们在遍历到物品
i
i
i的时候,并不选取它,所以剩余重量就没有变,状态变为遍历
i
+
1
i+1
i+1个物品;
d
(
i
+
1
,
j
−
w
[
i
]
)
+
v
[
i
]
d(i+1,j-w[i])+v[i]
d(i+1,j−w[i])+v[i]我们在遍历到物品
i
i
i的时候,选取它加入背包,所以剩余重量
j
j
j就要减去物品
i
i
i的重量
w
[
i
]
w[i]
w[i], 当前可能最大权重加上物品
i
i
i的权重
v
[
i
]
v[i]
v[i];
从计算的顺序过程来看:
我对刘汝佳的代码做了一点修改
for(int i = n; i >= 0; i——)
for(int j = 0; j <= C; j++){
if(i==n)
d[i][j]=0;
else
if(j >= w[i])
d[i][j]=max(d[i+1][j],d[i+1][j-w[i]]+v[i]);
}
先算的是
d
(
n
,
j
)
d(n,j)
d(n,j),注意,代码里面i有n+1个,物品编号从零开始,
i
=
n
i=n
i=n时,代表所有n个物品都已经遍历完但是一个都不选时的情况,初始要将其设为0;
之后从下往上遍历,所以计算的时候是先算后来的情况。
对于
j
j
j从0开始采取滚动数组时,如果不仅仅要求输出最大权重,也要输出最大权重时的重量的话
对于代码
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i++){
scanf("%d%d", &V, &W);
for(int j = C; j >= 0; j——)
if(j >= V) f[j] = max(f[j], = f[j-V]+W);
}
会出现多个最大重量都有最大权重的情况,
j
>
m
a
x
(
w
)
j>max(w)
j>max(w) 时只看
f
(
j
)
f(j)
f(j)是没有问题的;
但是想得到准确的
w
w
w,会混入超过的情况
所以需要
memset(f, -1, sizeof(f));
f[0]=0;
坑了我几个小时