【解题报告】01背包

这应该是最基础的背包问题了,但正因为他的基础,他的思想会被用在很多DP题中,所以这里有必要对他剖析一下。

我们应该掌握的方法有两种

1、二维数组。
2、滚动数组。

后面那个一看就要高级一些,但是确实对动归没有太大的帮助,所以大家一定要把第一种方法学好!第二种方法我不做解释,只会黏贴代码,大家认真脑补一下应该也是可以理解的。

题目链接:
01背包问题

二维数组法:

这里定义背包叫做f[i][j],i代表前i个物品的总重为j,f[i][j]一起表示前i个物品的总共价值,所以我们就可以很明显的写出动态转移方程式:

    if(w[i]<=v) f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i]);
    else f[i][v]=f[i-1][v];//important

然后大家应该都懂了,至于有些人问为什么中间看着这么别扭不直接这样写:

if(w[i]<=v) f[i+1][v+w[i]]=max(f[i][v]+c[i],f[i+1][v+w[i]]);
······ 

这当然是有原因的,是因为害怕一直往后扔会出现重复的情况!!!

下面上代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
int m,n;
int w[35],c[35];
int f[35][205];
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&w[i],&c[i]);
    }
    for(int i=1;i<=n;++i)
    {
        for(int v=m;v>0;--v)
        {
            if(w[i]<=v) f[i][v]=max(f[i-1][v],f[i-1][v-w[i]]+c[i]);
            else f[i][v]=f[i-1][v];//important
        }
    }
    printf("%d",f[n][m]);
    return 0;
}

P.s:中间加important的地方一定不要漏写了!

滚动数组法:

直接贴代码,大家脑补吧!

#include<cstdio>
#include<cstring>
using namespace std;
int bag[305];
int m,n;
int main()
{
    scanf("%d%d",&m,&n);
    int a,b;
    int limit=0;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&a,&b);
        for(int j=limit;j>=0;--j)
        {
            if(bag[j]!=0||(j==0))
            {
                if(bag[j+a]<bag[j]+b&&j+a<=m)
                {
                    bag[j+a]=bag[j]+b;
                }
                if(limit<j+a)
                limit=j+a;
            }
        }
    }
    int ans=-1;
    for(int i=0;i<=m;++i)
    {
        if(bag[i]>ans)
        ans=bag[i];
    }
    printf("%d",ans);
    return 0;
}

谢谢采纳!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值