01背包:
有n个物品,每个物品对应的价值和体积,且每个物品只能选一次,背包体积为V求背包所能装物品的最大价值
#include<iostream>
#include<cstdio>
const int maxn=10002;//n表示物品个数
int f[maxn],v[maxn],val[maxn],V,n;//V表示背包体积
using namespace std;//v[]表示物品的体积,
int main()//val[]表示物品的价值
{
scanf("%d%d",&n,&V);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&v[i],&val[i]);
}
for(int i=1;i<=n;i++)
for(int j=V;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+val[i]);
printf("%d",f[V]);
return 0;
}
完全背包:
和01背包基本类似,不同的只是每种物品可以取无数次;
对于完全背包的一维递推方程,我们只需要更改一下循环方向即可
for(int i=1;i<=n;i++)
for(int j=v[i];j<=V;j++)
f[j]=max(f[j],f[j-v[i]]+val[i]);//完全背包代码核心;
多重背包:
对于每一件物品我们对其规定件数(最多能使用多少件),我们可以对于每一种物品,枚举其件数,对于每一件物品,我们对其的状态只有两种:拿,不拿;所以我们可以转化成为01背包来求解
//第一层我们枚举物品种类
//第二层我们枚举背包体积;
//第三层我们枚举每种物品的个数
for(int i=1;i<=n;i++)
for(int j=V;j>=0;j--)
for(int k=0;k<=c[i];k++)
if(k*v[i]>j) break;//注意特判
else f[j]=max(f[j],f[j-k*v[i]]+k*val[i]);
printf("%d",f[V]);
分组背包:
我们来看一下什么是分组背包?
有N件物品和一个容量为V的背包,对于每一件物品给出该物品的体积价值和组别,由于每组的物品之间相互冲突,所以对于每组物品我们最多选择一件,求解将哪些物品装入背包可使体积总和不超过背包容量且价值最大;
也就是说我们可以从分组的角度来看,这其实是一个01背包问题,选或不选一个组的某一个物品:
对于分组背包我向大家推荐一种存储方式,这种方式让代码简洁易懂
我们在存储组数的时候可以开一个二维数组a[][],用a[i][0]来表示组别为i的物品的个数;
然后用a[i][j]来表示组别为i的第几的物品,
附上伪代码:
for k=所有的组数
for v=V...0;
for 所有的i属于k组的
f[v]=max(f[v],f[v-v[a[k][i]]]+val[a[k][i]]])
大家可以好好体会一下a[][]这个二维数组的巧妙。