一丶01背包的概念
有n件物品和一个容量为m的背包,每件物品只有一件(重点)。第i件物品的质量为w[i],其价值为v[i]。我们需要求得在不超过最大容量的情况下我们放入什么物品可以获得最大价值总和。
二丶状态方程
我们可以根据物品和容量确定一个状态,第i件物品放在背包中,总容量不超过j的情况下,我们可以获得的最大价值为dp[i][j]。
如果j小于w[i]:
dp[i][j] = dp[i-1][j]
如果j大于或等于w[i],小于或等于m:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
下面是一个 模板
。
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
if(j<w[i])
dp[i][j] = dp[i-1][j];
else
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
}
}
三丶我们可以进一步简化空间复杂度:
假设我们现在计算第i-1件物品,我们会发现:
dp[v]和dp[v-w[i]] (即dp[i-1][v]和dp[i-1][v-w[i]])均是第i-1件物品的结果,这就造成了空间的浪费,可以将状态方程优化一下
dp[j] = max(dp[j],dp[j-w[i]]+v[i])
下面直接进行代码实现
。
for(int i=1;i<=n;i++)
{
for(int j=m;j>=w[i];j--)//必须反向枚举!防止上一层dp[0,1....j-1]被覆盖
{
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
四丶例题
链接: link.
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[1010],num[1010];
int main()
{
int n,m;
while(cin>>n&&n)
{
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
cin>>num[i];
}
sort(num,num+n);
cin>>m;
if(m<5)
{
cout<<m<<endl;
continue;
}
m-=5;
for(int i=0;i<n;i++)
{
for(int j=m;j>=num[i];j--)
{
dp[j] = max(dp[j],dp[j-num[i]]+num[i]);
}
}
cout<<m+5-dp[m]-num[n-1]<<endl;
}
return 0;
}