题目描述
https://www.acwing.com/problem/content/2/
样例输入
略
样例输出
略
算法描述
我们的状态数组$f[i][j]$
指在背包有$j$的容量,只有前$i$件物品时的最大价值
由于每种物品只有选与不选两种情况
所以如果容量允许,那么$f[i][j]$只有两种选择
选择第$i$件物品,或不选
(状态转移方程见代码)
然鹅,我们可以使用一些奇妙的手段去掉数组的一维,是空间复杂度更低
即去掉$i$这一维,使用数组表示背包有$j$的容量时的最优解
这里有个细节,就是在进行递推的时候,$j$必须从大到小进行遍历
否则会使用一个更新过的值更新接下来的值
具体见代码
时间复杂度
$O(N*M)$
示例代码
优化前
#include <iostream>
using namespace std;
int f[1000][1000];
int w[1000];
int v[1000];
int main()
{
int m,n;
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>w[i]>>v[i];
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j]=f[i-1][j];
if(j>=w[i])
{
if(f[i][j]<f[i-1][j-w[i]]+v[i])
f[i][j]=f[i-1][j-w[i]]+v[i];
}
}
}
cout<<f[n][m];
return 0;
}
优化后
#include <bits/stdc++.h>
using namespace std;
int f[1000];
int w[1000];
int v[1000];
int main()
{
int m,n;
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>w[i]>>v[i];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=w[i];j--)
{
f[j]=max(f[j],f[j-w[i]]+v[i]);
}
}
cout<<f[m];
return 0;
}