1.完全背包
每种物品无限
dp[i,j]=max(dp[i-1,j] dp[i-1,j-v]+w dp[i-1,j-2*v]+2*w dp[i-1,j-3*v]+3*w......... dp[i-1,j-k*v]+k*w )
说明(k+1)*v>j,所以下一个也是到k为止
dp[i,j-v]=max(dp[i-1,j-v] dp[i-1,j-2*v]+w dp[i-1,j-3*v]+2*w......... dp[i-1,j-k*v]+(k-1)*w )
所以dp[i,j]=max(dp[i-1,j] dp[i,j-v]+w)
用一个状态来代替多个状态
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n,V;
int v[N],w[N];
int dp[N];
int main()
{
cin>>n>>V;
for(int i=1;i<=n;i++)
{
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;i++)
{
for(int j=v[i];j<=V;j++)
{
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
}
cout<<dp[V]<<endl;
return 0;
}
因为用到的元素是同层前面的,和上一层正上面,所以要从左往右
2.多重背包
每种物品有限定个数s
dp[i,j]=max(dp[i-1,j] dp[i-1,j-v]+w dp[i-1,j-2*v]+2*w ........ dp[i-1,j-s*v]+s*w )
dp[i,j-v]=max(dp[i-1,j-v] dp[i-1,j-2*v]+w ........ dp[i-1,j-s*v]+(s-1)*w dp[i-1,j-(s+1)*v)]+s*w]
对应不上了,所以不能用完全背包的优化方法
用打包的方法,把有限的物品用二进制方式分成一个个小堆,这些小堆可以拼出s内的任意数量,
就此转化为01背包
#include <bits/stdc++.h>
using namespace std;
int n,V;
struct Good
{
int _v,_w;
};
vector<Good> arr;
int main()
{
cin>>n>>V;
arr.push_back(Good());
while(n--)
{
int v,w,s;
cin>>v>>w>>s;
int sum=0;
for(int i=0;i<=log2(s);i++)//最多也就用这么多位了
{
if(sum+(1<<i) <=s)
{
Good good;
good._v= v*(1<<i);
good._w= w*(1<<i);
arr.push_back(good);
sum+=(1<<i);
}
}
if(sum <s)
{
Good good;
good._v= v*(s-sum);
good._w= w*(s-sum);
arr.push_back(good);
}
}
int dp[V+10]={0};
for(int i=1;i<=arr.size();i++)
{
for(int j=V;j>=1;j--)
{
if(arr[i]._v<= j)
{
dp[j] =max(dp[j], dp[j-arr[i]._v]+arr[i]._w);
}
}
}
cout<< dp[V];
return 0;
}
因为用到的元素是上一层前面的和上一层正上面的,所以要从右往左
3.滚动数组
时间复杂度不会优化,空间上可以优化
先写出不优化的版本,再根据推导所需的前置元素来调整dp顺序来优化