01背包-题目
01背包的经典问题是:
一个小偷拿着一个容量有限(容量设为w)的背包去商店偷东西,每个商品都有自己的体积v和价值c,并且每个商品只有一件。小偷的目的就是用这个容量有限的背包装满价值总量最大的东西。 现在给出n件商品的体积 𝑣𝑖 (i从1到n) 和价值 𝑐𝑖(从1到n)以及背包的容量w,请求出在这n件商品中用一个容量为w的背包能够拿到的商品的最大价值是多少?
01背包的特点是:每种物品仅有一件,可以选择拿或不拿
那么,他的状态转移方程是什么呢?(动态规划·入门(最长上升子序列,初级) 请点我!)
请注意,这体用贪心方法是不能AC的,因为如果两个物品的价值加起来大于当前最大的物品价值 ,用贪心的方法做就会WA,并且,有两种情况:一种是因为背包装不下了所以不拿;而另一种就是不拿比拿更划算。
我们可以将dp[ i ][ j ]看作前 i 种物品的体积是 j
那么拿的话,i种物品(种类)就要-1,背包容积就要减去当前物品的体积,那么完整的就是:
if(j<v[i])
{
dp[i][j]=dp[i-1][j];
}
else
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+c[i]);
}
需要注意,01背包需要逆序求解,所以完整代码是:
#include<bits/stdc++.h>
using namespace std;
int c[25],v[25],dp[25][105],n,w;
int main()
{
cin>>n>>w;
for(int i=1;i<=n;i++)
{
cin>>c[i];
}
for(int i=1;i<=n;i++)
{
cin>>v[i];
}
for(int i=1;i<=n;i++)
{
for(int j=w;j>=1;j--)
{
if(j<v[i])
{
dp[i][j]=dp[i-1][j];
}
else
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+c[i]);
}
}
}
cout<<dp[n][w];
return 0;
}
但是,我们需要优化空间,该怎么做呢?
我们知道,如果拿不了的话,当前状态和上一个状态是一样的,所以dp[i][j]中的i可以省略!
那么就改为:
#include<bits/stdc++.h>
using namespace std;
int c[25],v[25],dp[105],n,w;
int main()
{
cin>>n>>w;
for(int i=1;i<=n;i++)
{
cin>>c[i];
}
for(int i=1;i<=n;i++)
{
cin>>v[i];
}
for(int i=1;i<=n;i++)
{
for(int j=w;j>=1;j--)
{
if(j<v[i])
{
dp[j]=dp[j];
}
else
{
dp[j]=max(dp[j],dp[j-v[i]]+c[i]);
}
}
}
cout<<dp[w];
return 0;
}