// 前面章节中,我们学会了用贪心算法解决部分背包问题。本节,我们学习如何用动态规划算法解决 0-1 背包问题
// 虚拟一个场景,商店中拥有 5 件商品,它们各自的重量和收益分别是:
//商品 1:重量 1 斤,收益 1 元;
//商品 2:重量 2 斤,收益 6 元;
//商品 3:重量 5 斤,收益 18 元;
//商品 4:重量 6 斤,收益 22 元;
//商品 5:重量 7 斤,收益 28 元。
//
//所有商品不可再分,顾客要么“整件”购买商品,要么放弃购买。一个小偷想窃取商品,
// 他的背包只能装 11 斤商品,如何选择商品才能获得最大的收益呢?
package main
import (
"fmt"
"math"
"strconv"
)
//背包的最大承重
var W int = 11
//商品的种类
var N int = 5
func knapsack01(kres [][] int, kw [] int, kv [] int) {
// 逐个遍历每个商品
for i := 1; i <= N; i++ {
// 求出从1到W各个载重对应的最大收益
for j := 1; j <= W; j++ {
//如果背包载重小于商品总重量,则该商品无法放入背包,收益不变
if j < kw[i] {
fmt.Printf("%d j < kw[i]result:%d\n",j,kres)
kres[i][j] = kres[i-1][j]
} else {
fmt.Printf("%d j >= kw[i]result:%d\n",j,kres)
//比较转入该商品和不装该商品,那种情况获得的收益更大,记录最大收益
kres[i][j] = int(math.Max(float64(kres[i-1][j]), float64(kv[i]+kres[i-1][j-kw[i]])))
}
}
}
fmt.Printf("knapsack01 result:%d\n",kres)
}
// 追溯选中的商品
func selectPackage(sres [][] int, sw [] int, sv [] int) (string) {
var n int = N
var bagw int = W
var select_res string
for ; ; {
if n <= 0 {
break
}
// 如果在指定载重量下,该商品对应的收益和上一个商品对应的收益相同,则表明未选中
if sres[n][bagw] == sres[n-1][bagw] {
fmt.Printf("%d ==result:%d\n",n,sres)
n--
} else {
fmt.Printf("%d !=result:%d\n",n,sres)
select_res = select_res + "(" + strconv.Itoa(sw[n]) + "," + strconv.Itoa(sv[n]) + ")"
// 删除被选中商品的承重,以便继续遍历
bagw = bagw - sw[n]
fmt.Printf("%d bagw:%d\n",n,bagw)
fmt.Printf("%d sw[n]:%d\n",n,sw[n])
n--
}
}
fmt.Printf("selectPackage result:%d\n",sres)
return select_res
}
func main() {
// w[]存储各商品的重量
w := [] int{0, 1, 2, 5, 6, 7}
// v[]存储各商品的价值
v := [] int{0, 1, 6, 18, 22, 28}
// result[][]存放最终的结果
result := make([][] int, N+1)
for i := range result {
result[i] = make([]int, W+1)
}
knapsack01(result, w, v)
fmt.Printf("背包承重为%d,最大收益为%d\n", W, result[N][W])
fmt.Printf("选择了:%s", selectPackage(result, w, v))
}
11-17
333
