动态规划-01背包问题

背包问题是很经典的动态规划问题,变种问题也很多,最基本的问题是01背包问题

问题描述:

有n 个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

i:物品1234
w:体积2345
v:价值3456

分析:

01背包问题可以看做是物品的序列X=[x_1,x_2,x_3,...x_i],其中x_i=[0,1],表示第i个物品放或者不放。状态转移矩阵是一个二维矩阵,其中行表示物品,列表示背包容量。和之前讲最长公共子序列一样,考虑背包装完后最优的时候,那么拿出最后一件后将背包容量缩小还是最优的。

状态转移公式有如下性质

1. 初始状态i=0 j=0,表示背包容量为0,没有物品,此时价值是0

2. 放入的时候有两种条件:

    (1) 当w(i)>j,此时放不进去物品i,价值V(i,j)=V(i-1,j)

    (2) 当w(i)<=j,此时能放进物品i,但不一定放进去能达到最优

         V(i,j)=max(V[i-1,j],V[i-1,j-w(i)]+V(i))

         之所以放进去也不一定最优,因为上面矩阵保存的都是当前状态最优的时候,刚能放进去的时候表示的是只有物品i的时候能放进去j中,但是拿出来了之前放的所有的东西,不一定就是最优了,所以有两个分支。不放进去就是i-1时的状态,放进去了要找i-1的时候背包空间是j-w(i),再放i的时候正好背包满了这时候最优,看两者哪个更大。

实现

w=[2,3,4,5]
v=[3,4,5,6]
bag=8
c=[[0 for i in range(bag+1)] for j in range(len(w)+1)]

for i in range(1,len(w)+1):
    for j in range(1,bag+1):
        if w[i-1]>j:  #放不下i,不放
            c[i][j]=c[i-1][j]
        else:   #放得下i,但放入不一定最优
            c[i][j]=max(c[i-1][j],c[i-1][j-w[i-1]]+v[i-1])
print(c[len(w)][bag])

 观察之前的状态转移方程和上面的代码,可以发现每一次更新状态V[i][j]的时候只用到了V[I-1]这一层,所以状态转移矩阵可以精简为一个一维数组,在更新V[i][j]的时候此时数组的状态是V[i-1]。但是我们要从后往前更新数组,因为用到了V[i-1]。

b=[0 for i in range(bag+1)]
for i in range(len(w)):
    for j in range(bag+1)[::-1]:
        if w[i]<=j:
            b[j]=max(b[j],b[j-w[i]]+v[i])
print(b)

如果我们想获得装了哪些物品那么只能用二维矩阵回溯,回溯的过程是:

从右下角开始,如果V[i][j]==V[i-1][j],说明物品i没有放,回溯到V[i-1][j]

如果不等于,说明物品i放了,回溯到V[i-1][j-w(i)]

 

参考

https://www.cnblogs.com/Christal-R/p/Dynamic_programming.html

https://blog.csdn.net/littlethunder/article/details/26575417

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值