【算法】动态规划解决01背包问题

// 前面章节中,我们学会了用贪心算法解决部分背包问题。本节,我们学习如何用动态规划算法解决 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))
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值