1. 01背包
背包的核心主要围绕着一个公式: f [ j ] = max (f [ j ],v[ j - v ] + w)。
样例 1
有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。
第 ii 件物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
代码如下
#include<iostream>
#define N 1010
using namespace std;
int main()
{
int n,m;
int v[N]={0},w[N]={0};
int f[N]={0};
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d%d",&v[i],&w[i]);//输入 只要记住下面的三行就行了
for(i=1;i<=n;i++)
for(j=m;j>=v[i];j--)//关键
f[j]=max(f[j],f[j-v[i]]+w[i]);//公式
printf("%d",f[m]);
return 0;
}
2. 完全背包
在01背包的基础上一个物品可以选择无数次,但是代码大致相同,由从大到小遍历改为从小到大。
把上述01背包标记 // 关键 的代码改为从小到大即可。
例如
for(j=v[i];j<=m;j++)//关键
样例 略;
3. 多重背包
多重背包最直接的方式为分为多个01背包,但通常数据较大就爆了,所以多重背包有多个优化方式,如:二进制优化,单调队列优化,,
直接写法:
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d%d%d",&v,&w,&p);//此处把输入加入循环当中,省略了单个物品的价值和重量的数组建立
for(j=m;j>=v;j--)//01背包,从大到小
for(k=1;k<=p&&k*v<=j;k++)//关键 遍历物品的件数
f[j]=max(f[j],f[j-v*k]+w*k);//公式
}
二进制优化:
思想:把每种物品的件数通过2的次方数表示。
如:
6=1+2+(3)
11=1+2+4+(4)
30=1+2+4+8+16+(9)
除了最后一个数;前几个数都为2的次方。
for(i=0;i<n;i++)//s[]每种的件数,v[]重量,w[]价值
{
r=1;
while(s[i]-r>0)//判断是否大于二的次方
{
s[i]-=r;
v[++p]=r*v1[i];
w[p]=r*w1[i];//整合价值和重量
r<<=1;//二进制移位,相当于*2
}
if(s[i]>0){//处理最后不是2的次方的数
v[++p]=(s[i])*v1[i];
w[p]=(s[i])*w1[i];
}
}
for(int j=1;j<=p;j++)//最后来个01背包就ok了
{
for(int i=m;i>=v[j];i--)
f[i]=max(f[i],f[i-v[j]]+w[j]);
}
单调队列优化:略
4. 二维费用背包
例:
有 N 件物品和一个容量是 V 的背包,背包能承受的最大重量是 M。
每件物品只能用一次。体积是 vi,重量是 mi,价值是 wi。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,总重量不超过背包可承受的最大重量,且价值总和最大
解
在体积限制的情况下加了个重量限制;
实质还是01背包:一维数组改为二维,并且在01背包的关键for容量循环加个for重量循环就行了。
关键
for(int j=v;j>=a;j--)//v总容量,a单个容量,m总重量,b单个重量
for(int k=m;k>=b;k--)
f[j][k]=max(f[j][k],f[j-a][k-b]+c);
代码
int f[N][N]={0};int main()
{
scanf("%d%d%d",&n,&v,&m);
for(int i=0;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
for(int j=v;j>=a;j--)
for(int k=m;k>=b;k--)
{
f[j][k]=max(f[j][k],f[j-a][k-b]+c);
}
}
printf("%d",f[v][m]);
}
5.分组背包
有 N 组物品和一个容量是 V 的背包。
每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。
求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
输出最大价值。
把组拆开,遍历就是01背包了
int f[N]={0},v[N]={0},w[N]={0};
int n,m,s;
int i,j,k;int main()
{
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%d",&s);
for(j=0;j<s;j++)
scanf("%d%d",&v[j],&w[j]);
for(j=m;j>=0;j--)
{
for(int k=0;k<s;k++)
{
if(j>=v[k])
f[j]=max(f[j],f[j-v[k]]+w[k]);
}
}
}
printf("%d",f[m]);
}