01背包
二维可以用一维滚动数组优化,只能选一个每个物品只有选和不选两种情况。
#include<iostream>
using namespace std;
const int N=1010;
int f[N];
int w[N];
int v[N]; int main()
{
int n,v1;
cin>>n>>v1;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
for(int j=v1;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[v1]<<endl;
return 0;
}
完全背包问题
也可以用滚动数组来算
状态转移方程可以更新为dp[i][j]=dp[i-1][j]和dp[i][j-v]+w
#include<iostream>
using namespace std;
const int N=1010;
int f[N];
int w[N];
int v[N]; int main()
{
int n,v1;
cin>>n>>v1;
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<=v1;j++)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[v1]<<endl;
return 0;
}
多重背包问题
每个物品有限定的个数可以选,问最大价值
要是暴力做n3的复杂度,用二进制优化,将每个数的数量分成logs个,可以用化成nlogs的复杂度。把每堆物品打包,最后当成01背包做。
#include<iostream>
using namespace std;
const int N=1110;
int f[N];
int s[N];
int v[N],w[N]; int main()
{
int n,v1;
cin>>n>>v1;
for(int i=1;i<=n;i++)
{
cin>>v[i]>>w[i]>>s[i];
}
int cnt=1;
for(int i=1;i<=n;i++)
{
int k=1;
int s1=s[i]; while(k<=s1)
{
v[cnt]=k*v[i];
w[cnt]=k*w[i];
cnt++;
s1-=k;
k*=2;
}
if(s1)
{
v[cnt]=s1*v[i];
w[cnt]=s1*w[i];
cnt++;
}
}
n=cnt;
for(int i=1;i<=n;i++)
for(int j=v1;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[v1]<<endl;
return 0;
}
分组背包问题
每个组里的物品只能选一个,这就需要用一个二维的数组w,v分别存放每组物品的价值和空间。
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int f[N];
int w[N][N],v[N][N];
int s[N]; int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
for(int j=0;j<s[i];j++)
{
cin>>v[i][j]>>w[i][j];
}
}
for(int i=1;i<=n;i++)
for(int k=m;k>=0;k--)
for(int j=0;j<s[i];j++)
if(k>=v[i][j])
f[k]=max(f[k],f[k-v[i][j]]+w[i][j]);
cout<<f[m]<<endl;
return 0;
}