背包问题本质上是动态规划的一种,一般也是通过状态转移方程式来解决问题,问题一般是以一个有固定容量或者承重的背包和一些固定体积,重量和价值的物品,填充背包从而使背包中物品的价值最大化
01背包
01背包中每个物品只有选或不选两种状态
主要关键点:01背包的主要难点就是在于状态转移方程式的确定,这一点其实也是所有动态规划的难点所在,另一个就是为何物体的体积是逆序遍历的?
代码如下:
func main() {
//背包容积
var v int
//物体数量
var n int
fmt.Scanf("%d", &n)
fmt.Scanf("%d", &v)
//物体体积
vslice := make([]int, n,n)
//物体价值
wslice := make([]int, n,n)
for i := 0; i < n; i++ {
fmt.Scan(&vslice[i], &wslice[i])
}
//记录当前体积能装入的最大价值
dp := make([]int, v+1, v+1)
for i := 0; i < n; i++ {
//体积从大到小开始遍历
for j := v; j >=vslice[i]; j-- {
//选择是否装入物品时的最大值进行更新
dp[j] = int(math.Max(float64(dp[j]), float64(dp[j-vslice[i]]+wslice[i])))
}
}
fmt.Println(dp[v])
}
完全背包
基本条件跟01背包类似,唯一不同的是每个物品可以无限次选择
代码如下:
主要的区别在于体积遍历时是从当前物品的体积开始遍历,与01背包相反
func main() {
//背包容积
var v int
//物体数量
var n int
fmt.Scanf("%d", &n)
fmt.Scanf("%d", &v)
//物体体积
vslice := make([]int, n,n)
//物体价值
wslice := make([]int, n,n)
for i := 0; i < n; i++ {
fmt.Scan(&vslice[i], &wslice[i])
}
dp := make([]int, v+1, v+1)
for i := 0; i < n; i++ {
//从小到大开始遍历
for j := vslice[i]; j <= v; j++ {
dp[j] = int(math.Max(float64(dp[j]), float64(dp[j-vslice[i]]+wslice[i])))
}
}
fmt.Println(dp[v])
}
关于01背包和完全背包的具体讲解
1 状态转移方程式
dp是记录当前体积能装入物品的最大价值,下面这个状态转移方程式的主要含义是通过对比物品装入背包和不装入背包的最大价值
dp[j] = int(math.Max(float64(dp[j]), float64(dp[j-vslice[i]]+wslice[i