01背包问题描述:有编号分别为a,b,c,d,e的N=5件物品,它们的重量w分别是2,2,6,5,4,它们的价值v分别是6,3,5,4,6,每件物品数量只有一个,现在给你个承重为M=10的背包,如何让背包里装入的物品具有最大的价值总和sum_v?
在DP(dynamic programming)问题中,01背包问题是比较基础和简单的了,但是网上很多人的讲解要么长长一大段,长篇公式理论,要么就是知识把状态转移方程列了出来,而没有说明为什么方程是这么写的,下面我力图将01背包问题中最简单最核心的概念和思路讲一下:
1. 此01背包问题本质上是穷举背包容量和可供选择的物品(意思是里面的物品可能会放进背包,可能不会放进背包),取得最优解,只不过在穷举的过程中,会根据状态转移方程,只计算可能获得的最优解的部分。
2. 为什么能列出状态转移方程?是因为每个状态的最优解,都是根据之前的状态的最优解获得的。具体到背包问题,有以下几点:
a) 当物品备选情况一致时,背包容量M越大,那么sum_v一定大于等于原来的值。
b) 背包容量M确定时,可供选择的物品N越多,那么sum_v一定大于等于原来的值。
c) 由a)和b)可得,sum_v的最大值就是当M和N取到最大值时的sum_v
c) 从思路上说,01背包问题有两个维度:背包容量M,和供选择物品数N。编程的本质是实现人类解决现实问题的思路。仔细想想,如果不借助计算机,你该如何解决这个问题?答案是,例如考虑M=1时,先考虑a能否放入背包,取得最大值,再考虑a和b能否放入背包(a和b都是备选,最终放入背包的可能是a,可能是b,也可能是ab),这时因此与之前只考虑a的情况相比,多了一个b,所以:
要先判断b能否单独放进背包,如果不能,那么考虑a和b的情况能取得的最大值,就是只考虑a的情况。
如果能,即b能够放进去,还有两种可能,对这两种可能性,要取最大值:
最终真的将b放进去;是否将a放进去是未知的
最终没有将b放进去(因为后面可能有比b更合适的物品放进去),是否将a放进去也是未知的
用数学的方式描述上段话:sum_v[i][j]表示将前i件物品列为备选,背包容量为j时,能获得的最大价值;w[i]表示第i件物品的重量,v[i]表示第i件物品的价值
if 1 >=w[2]: sum_v[2][1] = max(sum_v[1][j-w[2]] + v[2], sum_v[1][1]) else: sum_v[2][1] = sum_v[1][1]