背包问题(持续更新)

背包问题真的是学一遍忘一遍,所以这次打算记录一下思考历程,以便以后查看方便

0. 01背包

问题描述:有n个重量和价值分别为 wi,vi的物品。从这些物品中挑选出总重量不超过 V 的物品, 求所有挑选方案中价值总和的最大值。

基本思路:这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。状态转移方程:

f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

先说二维数组的方法:
不知道怎么说,直接上代码,然后详解代码意义8
思路都在注释里

//这个数组表示横行表示的是物品的体积,纵行表示的是第几个物品
//数组里的值为在包的体积为j,第i件物品的时候,所能得到的最大价值
int arr[100][100];
int w[100],c[100];//w数组是物品的价值(weight),c数组是物品的体积(cost)
int main()
{
    int n,v;//物品的个数和背包的体积
    scanf("%d %d",&n,&v);
    
    for(int i=1;i<n+1;i++)
    {
        scanf("%d %d",&w[i],&c[i]);//输入物品的价值和消耗
    }
    for(int i=1;i<n+1;i++)
    {
        for(int j=1;j<v;j++)
        {
            if(c[i]>j)
            {
                //当物品i的体积大于当前背包体积的时候,直接继承上一件物品最优状态
                //因为装不进去,arr数组每一个单位都是当前背包体积,当前见到的物品个数的情况下最优的
                //所以可以保持最优状态
                arr[i][j]=arr[i-1][j];
            }
            else
            {
                /*  当物品i的体积小于当前背包体积即能装进去的时候
                让不装此物品的价值和装了此物品的价值做比较,选择较大值作为该状态
                arr[i-1][j]为不装此物品的价值
                arr[i-1][j-c[i]]+w[i]为装此物品的价值,即上一行刚好空出c[i]体积大小
                物品时的最优状态,加上物品i的价值即为装i物品时的价值,然后比较这两者大小
                判断该体积下是否要装物品i   */
                arr[i][j]=max(arr[i-1][j],arr[i-1][j-c[i]]+w[i]);
            }
        }
    }
    //这样一个循环下来,arr[n][v]即为当书包的体积为v的情况下,n个物品所能带走的最大价值
}

二维数组的方法就是太浪费空间了,其实可以用滚动数组来实现该问题,这样可以大大减少空间的使用,因为在二维数组实际上可以发现有很多数据就是承接的上一行的,其实根本没有必要这样写,完全可以用一个一维数组来减少空间复杂度
下边贴一维数组解决方法,不贴注释了,理解二维数组一维数组也就不难理解了
我把滚动数组的每一次外循环后的值写了出来(神tm,我忘了printf大法了,自己手算花了一个变化图,嘤嘤嘤),如图:

在这里插入图片描述
一维数组01背包:

//这个数组表示横行表示的是物品的体积,纵行表示的是第几个物品
//数组里的值为在包的体积为j,第i件物品的时候,所能得到的最大价值
int arr[100];
int w[100],c[100];//w数组是物品的价值(weight),c数组是物品的体积(cost)

int main()
{
    int n,v;//物品的个数和背包的体积
    scanf("%d %d",&n,&v);
    
    for(int i=1;i<n+1;i++)
    {
        scanf("%d %d",&w[i],&c[i]);//输入物品的价值和消耗
    }
    for(int i=1;i<n+1;i++)
    {
        for(int j=v;j>=c[i];j--)
        {
            arr[j]=max(arr[j],arr[j-c[i]]+w[i]);
        }
    }
    //这样一个循环下来,arr[v]即为当书包的体积为v的情况下,n个物品所能带走的最大价值
}

先更到这里,饿了回家恰饭了,剩下的下午更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值