1.01背包问题
我们首先定义一个二维数组f,其中f[i][j]表示在前i个物品中取且总体积不超过j的取法中的最大价值。那么我们如何得到f[i][j]呢?我们运用递推的思想。由于第i个物品只有选和不选两种情况,当不选第i个物品时,f[i][j]=f[i-1][j],即取前i-1个物品且总体积小于等于j的所有取法中的最大价值;当选第i个物品时,我们要为第i个物品留出空间,此时f[i][j]=f[i-1][j-v[i]]+wi,即取前i-1个物品且总体积不能超过j-v[i]的取法中的最大价值再加上第i个物品的价值。因此代码如下:
#include<iostream>
#include<cmath>
using namespace std;
const int K = 1010;
int v[K],w[K],f[K][K];
int main()
{
//本来应该对f[0][0~V]进行初始化为0,但由于我们开的数组是全局变量,自动初始化为0,因此这一步省略了。
int N,V;
cin>>N>>V;
//一定要从下标1开始读入数据,因为后面是从下标1开始遍历物品的,如果从下标0开始读入,会遗漏第一个物品。
for(int i = 1;i<=N;i++) cin>>v[i]>>w[i];
//由于i-1应该大于等于0,所以从i=1开始遍历。
for(int i = 1;i<=N;i++)
{
for(int j = 0;j<=V;j++)
{
//只有在j>=v[i],即能放得下第i个物品的时候我们才有第二种情况。因此我们不妨直接先让f[i][j]继承f[i-1][j],然后再在满足条件时取两者中的最大值即可。
f[i][j] = f[i-1][j];
if(j>=v[i])
f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
cout<<f[N][V]<<endl;
return 0;
}
那么我们如何对代码进行优化呢?我们能不能让f[j]表示总体积小于等于j的取法中的最大价值呢?答案是肯定的。请看代码——
#include<iostream>
#include<cmath>
using namespace std;
const int K = 1010;
int v[K],w[K],f[K];
int main()
{
int N,V;
cin>>N>>V;
for(int i = 1;i<=N;i++) cin>></