0-1背包问题图解-Go语言

0-1背包问题图解-Go语言

问题:给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容重量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

  • 在选择装入背包的物品时,对每种物品i只有2种选择,即装入/不装入。
  • dp[i][j]表示前i 件物品体积不超过j 的情况下能达到的最大价值。
  • 边界条件:dp[1][j] = V[1],if j >= W[1]dp[i][1] = 0
  • 状态转移方程dp[i][j] = max(dp[i-1][j],dp[i-1][j-W[i]]+V[i]),j-W[i]>=0

对于这个问题我们要对这个二维dp数组有清晰地认识,对其遍历循序要有个清晰认识。

image-20220412194102159

对于一个dp[i][j]的值是由该图中的二维dp数组的上方与左上方的值来推算出来的。

image-20220412195101350

参考代码:

package main

import (
	"fmt"
)

func main() {
	const maxN, maxW = 1000, 1000000
	weight := []int{2, 2, 6, 5, 4}
	values := []int{6, 3, 5, 4, 6}

	n := len(weight)
	mw := 10
	// dp数组
	dp := [maxN][maxW]int{}
	var max = func(a, b int) int {
		if a > b {
			return a
		}
		return b
	}
	// 初始化边界条件
	for j := 1; j <= mw; j++ {
		if j >= weight[0] {
			dp[1][j] = values[0]
		}
	}
	// 状态遍历
	for i := 2; i <= n; i++ {
		for j := 2; j <= mw; j++ {
			if j >= weight[i-1] {
				// 状态转移方程
				dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i-1]]+values[i-1])
			} else {
				dp[i][j] = dp[i-1][j]
			}
		}
	}
	// 最终结果
	fmt.Println(dp[n][mw])
	// 输出dp数组
	for i := 1; i <= n; i++ {
		for j := 1; j <= mw; j++ {
			fmt.Print(dp[i][j], " ")
		}
		fmt.Println()
	}
}

对于这这道题,如果所有可装入背包的物品不多的话,我还可以暴力枚举。因为每一个物品我们可以装入背包或不装入,这就对应着两种状态,这样我们可以使用二进制枚举。

参考代码:

package main

import "fmt"

func main() {
	weight := []int{2, 2, 6, 5, 4}
	values := []int{6, 3, 5, 4, 6}

	n := len(weight)
	m := 10

	var max = func(a, b int) int {
		if a > b {
			return a
		}
		return b
	}

	vs, ws, res := 0, 0, 0
	for i := 0; i < 1<<n; i++ {	// 枚举所有可能的状态
		vs, ws = 0, 0
		for j := 0; j < n; j++ {
			if i&(1<<j) > 0 {	// 检查状态
				vs += values[j]
				ws += weight[j]
			}
		}
		if ws <= m {	// 筛选符合条件的状态
			res = max(res, vs)
		}
	}

	fmt.Println(res)
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值