朴素解法 -- 二维数组
初始化
因为f[N][N]定义在堆中,会自动初始化为零。此时算出背包容量为M的时候的最大值,未必是全部装满的最大值,背包中可能会有剩余。若想算出正好装满的,需要对初始化做改动:将f[N][0]复制为零,其余的赋值为负无穷,这样在状态转移的时候可以保证所有可以作为更改的项全部都由f[N][0]转移过来,其他的都太小在取max的时候选不到。
状态转移方程
f[i][j] 的状态表示在有i个物体、j个背包体积的情况下所选最优解。该状态由f[i-1]推出。从f[i-1]到f[i]有两种选择情景,分别为选择f[i]与不选择f[i]。
选择f[i] : f[i][j] = f[i - 1][j - wei[i]] + val[i] ;
不选择f[i] : f[i][j] = f[i - 1][j];
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N][N];
int n, m;
int wei[N];
int val[N];
int main ()
{
cin >> n >> m;
for(int i = 1; i<= n ; i++) cin >> wei[i] >> val[i];
for(int i = 1; i<= n ; i++)
{
for(int j = 0; j<=m ; j++)
{
f[i][j] = f[i-1][j];
if( j >= wei[i]) f[i][j] = max(f[i][j] , f[i-1][j - wei[i]] + val[i]);
}
}
cout << f[n][m];
return 0;
}
优化 : 二维数组变为一维数组
针对选择f[i]的情况 : f[i][j] = f[i - 1][j - wei[i]] + val[i] ; 变为一维数组之后 : f[j] = f[j - wei[i]] + val[i]; 此时要保证使用的f[j - wei[i]]是在f[i-1]中算出的数据,但是如果保持原循环 j from 0 to m 的顺序,则所用f[j - wei[i]] 则是f[i]中算出的数据,所以循环改为 j from m to wei[i] (如果剩余重量不足以装下 i 物体的话,则不需要运算)
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m;
int f[N];
int wei[N];
int val[N];
int main ()
{
cin >> n >> m;
for(int i = 1; i<= n ; i++) cin >> wei[i] >> val[i];
for(int i = 1 ; i <= n; i++)
{
for(int j = m ; j >= wei[i] ; j-- )
{
f[j] = max(f[j] , f[j - wei[i]] + val [i]);
}
}
cout << f[m];
return 0;
}