第一周学习总结(背包)

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]);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值