【0-1背包问题】
问题描述:
有n个物品和一个最多能承受重量为 W 的背包,其中第 i 件物品的重量是weight [ i ] ,所对应的价值为value[i],每一件物品只有一件(即只能放入背包一次),求解将哪些物品放入背包后得到的背包中物品的总价值最大?
递归分析
weight物品的重量,那么我们从0开始选择,就存在选或者不选的两种情况,在这两种情况之下,那么背包的重量也存在两种情况,可以装下或者无法装下,递归函数如下:
// weight 物品的容量
// value 物品的价值
// index 当前开始选择物品的索引
// bag 背包的剩余容量
func process(weight,value []int,index,bag int) int{
// 背包容量没有剩余
// 严格小于0
if bag < 0 {
return -1
}
// 到达最后一个货物
if index = len(weight) {
return 0
}
// 不选择当前货物
p1 := process(weight,value,index+1,bag)
p2 := 0
// 选择当前货物,则bag会减少,并且需要判断选择当前货物之后容量是否还需要继续选择
next := process(weight,value,index,bag-weight[indx])
if next != -1{
p2 = value[index] + next
}
// 返回最大值
if p1 > p2 {
return p1
}
return p2
}
动态规划
动态规划实际上是将递归过程中产生的重复的值进行缓存,然后后续在使用重复值的时候直接选择。
// weight 物品的容量
// value 物品的价值
// index 当前开始选择物品的索引
// bag 背包的剩余rongliang
func dp(weight, value []int, bag int) int {
m := len(weight)
// 首先该方法中weight,value是常量,所以动态规划表中不用考虑
dp := make([][]int, m+1)
// 所有值初始化为0
for i := 0; i < m+1; i++ {
dp[i] = make([]int, bag+1)
}
for index := m - 1; index >= 0; index-- {
for rest := 0; rest <= bag; rest++ {
// p1 := process(w, v, index+1, bag)
p1 := dp[index+1][rest]
p2 := 0
next := 0
// 选择当前物品,背包容量减小,背包容量合法性
if rest - weight[index] >= 0 {
p2 = value[index] + dp[index+1][rest-weight[index]]
}
// 选择最大价值
if p1 > p2 {
dp[index][rest] = p1
} else {
dp[index][rest] = p2
}
}
}
return dp[0][bag]
}