问题一、背包问题中”恰好”和”不大于”
和初始状态有关,不大于的话所有体积都可以作为初始状态
恰好的话,只有一个初始状态,那就是 $f[0][0] = 0$
①:不大于的情况
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
{
f[i][j] = f[i - 1][j];
if(j - v[i] >= 0) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= m; j ++ )
cout << f[i][j] << " ";
cout << endl;
}
// 输入
// 3 3
// 2 1
// 1 100
// 1 100
// 输出
// 0 1 1
// 100 100 101
// 100 200 200
②:恰好的情况
将其他状态初始化为负无穷,令$f[0][0] = 0$
memset(f, -0x3f, sizeof f);
f[0][0] = 0;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= m; j ++ )
{
f[i][j] = f[i - 1][j];
if(j - v[i] >= 0) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= m; j ++ )
cout << f[i][j] << " ";
cout << endl;
}
// 输入
// 3 3
// 2 1
// 1 100
// 1 100
// 输出
// -1044266559 1 -1044266558
// -1044266459 1 101
// -1044266459 1 101
③:总结
两者的关键之处就在于
$$f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i])$$
如果设置为负无穷,当f[i - 1][j - v[i]]这个状态不存在时,f[i][j]这个状态也不会存在。
如代码②所示:
$ \ $
第一层 只有满足当体积为v[1]的时候,才会更新(因为当k = 2时,$f[1 - 1][j - v[i]] = f[0][0]$ 这个状态存在)
$ \ $
第二层 只有满足当$f[2 - 1][j - v[2]] \ 和 \ f[2 - 1][j]$存在的时候,才会更新
$ \ $
$…$
$ \ $
第n层 只有满足当$f[n - 1][j - v[n]] \ 和 \ f[n - 1][j]$存在的时候,才会更新
$ \ $
这样,就严格保证f[i][j]是体积恰好等于j的方案了