01背包理解及空间优化(动态规划)

目录:

  • 问题描述
  • 问题分析
  • 构造最优解
  • 空间优化

1. 问题描述:给定N个物品和容量为C的背包,每个物品的重量是Wi,价值为Vi,每个物品只有选择装入背包或者选择不装如背包。求如何选择能使得背包装入的总价值最大。

2. 问题分析:使用一个二维数组来存储每种状态。声明二维数组大小为m[n][c],其中m[i][j]表示在前i个物品中进行适当的选择,使得在不超过背包容量j时能获得最大价值。分析m[i][j]的计算方法

  • case(1): j < w[i] ,即背包容量为j时无法放下第i个物品,此时选择不装入该物品。则m[i][j] = m[i-1][j] , 此等式表示面对第i个物品时不选择,并且该值等于前i-1个物品选择时最大价值。
  • case(2): j >= w[i],即背包的容量可以放下第i个物品,但因为要满足价值最大化,所以要考虑是否将物品i装入背包中。如果装入包中,则m[i][j] = m[i-1][ j - w[i] ] + v[i],其中m[ i-1 ][ j-w[i] ]指的是考虑了i-1件物品,背包容量为j-w[i]时的最大价值,其本质是为第i件物品腾出了w[i]的空间。如果不装入包中,则m[i][j] = m[i-1][j]。
  •  根据上面的分析,可以得出状态转移方程:
if(j >= w[i]):
    m[i][j] = max(m[i-1][j], m[i-1][j-w[i]] + v[i])
else:
    m[i][j] = m[i-1][j]
  •  实现代码:
for(int i=1;i<=n;i++)  // n为物品个数
    {
        for(int j=1;j<=c;j++)  // c 为背包容量
        {
            if(j>=w[i])  // 选取
                m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]); //取较大值
 
 
            else // 不选
                m[i][j]=m[i-1][j];
        }
    }

根据上面可以计算出二维数组最后一个值m[n][c]即为最大价值

3.构造最优解(前面工作可以得到最大价值,但是不知道是选取了哪些物品而得到的最大值)

  • 思路:m[n][c]为最优值,如果m[n][c]=m[n-1][c] ,说明有没有第n件物品都一样,则x[n]=0 ; 否则 x[n]=1。当x[n]=0时,由x[n-1][c]继续构造最优解;当x[n]=1时,则由x[n-1][c-w[i]]继续构造最优解。以此类推,可构造出所有的最优解。
  • 代码实现:
void traceback()
{
    for(int i=n;i>1;i--)
    {
        if(m[i][c] == m[i-1][c])
            x[i] = 0;
        else
        {
            x[i] = 1;
            c -= w[i];
        }
    }
    x[1] = (m[1][c]>0) ? 1 : 0;
}

 

4. 空间优化

  • 思路:由0-1背包的状态转移方程 m[i][j] = max{m[i-1][j-w[i]]+v[i],m[i-1][j]}的特点,知道当前状态仅依赖前一状态的剩余容量与当前物品重量v[i]的关系。根据这个特点,我们可以将m降到一维即m[j] = max{m[j],m[j-w[i]]+v[i]}。从这个方程中我们可以发现,有两个m[j],但是要区分开。等号左边的m[j]是当前i的状态,右边括号中的m[j]是第i-1状态下的值。
  • 优化代码:
  • void FindMaxBetter()//优化空间后的动态规划
    {
        int i,j;
        for(i=1;i<=number;i++)
        {
            for(j=capacity;j>=0;j--)
            {
                if(B[j]<=B[j-w[i]]+v[i] && j-w[i]>=0 )//二维变一维
                {
                    B[j]=B[j-w[i]]+v[i];
                }
            }
        }
    }
  • 备注:优化后的代码只可以求出最大价值,并不能构造最优解(也就是不知道选择了哪些物品使价值最大化)
  • 当不明白的时候,手动推一遍是最好的方法。

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值