我们可以把物品依次排列,整个问题就分解为了n个阶段,每个阶段对应一个物品怎么选择。先对第一个物品进行处理,选择装进去或 者不装进去,然后再递归地处理剩下的物品。描述起来很费劲,我们直接看代码,反而会更加清晰一些。
package main
import "fmt"
//总的思想是,把n个物体依次排列
//对每个当前物体考虑两种情况,一种是不放进入背包后,递归遍历后边的各种情况
//另一种是放进入背包后,再递归遍历后边的各种情况
//出递归条件,已经访问了最后一个物体了或者已经是背包最大容量了
var maxW int //表示背包能装的最大重量
var curAnswer []int //当前背包状态,下标表示物体,值表示是否装进背包
var bestAnswerMap = make(map[int][][]int) //存储最佳答案,key背包重量,值为多种情况,所以为数组
func f(i, cw int, items []int, n, w int) {
if curAnswer == nil { //其实只初始化了一次
curAnswer = make([]int, n) //curAnswer[x]值为1,表示x加入背包
}
if cw == w || i == n {
if cw != 0 && cw >= maxW { //cw是在背包允许的重量范围里的值,取其中最大值
maxW = cw
//如下是为了打印出最佳结果
bst := make([]int, n)
for j := 0; j < n; j++ {
bst[j] = curAnswer[j]
}
if val, ok := bestAnswerMap[maxW]; ok {
val = append(val, bst)
bestAnswerMap[maxW] = val
//map中的元素是不能寻址的,val,ok这种方式,拿到的是副本
} else {
temp := make([][]int, 0)
temp = append(temp, bst)
bestAnswerMap[maxW] = temp
}
//以上是为了打印出最佳结果
}
return
}
curAnswer[i] = 0 //考虑不放进入
f(i+1, cw, items, n, w) //考虑不放入当前物体的情况
if cw+items[i] <= w {
curAnswer[i] = 1 //考虑放进入背包
f(i+1, cw+items[i], items, n, w) //考虑放入当前物体的情况
}
}
func main() {
a := []int{1, 2, 3, 4, 10, 5, 6, 7, 8, 9}
f(0, 0, a, 10, 10)
fmt.Println(maxW)
for k, v := range bestAnswerMap {
fmt.Printf("key is %d, value is %v\n", k, v)
fmt.Println("=======================")
}
}