代码随想录day35 || 416 分割等和子集

背包问题

有n件物品和一个最多能背重量为 w 的背包。第i件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
image

copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
// pake // // @Description: // @param weights: 物品i对应重量 // @param value: 物品i对应价值 // @param n: 背包容量 // @return int func pake(weights, value []int, n int) { // dp 五部曲 // 确定dp数组以及下标的含义: dp[i][j] 代表容量为j的背包装前i个物品获得的最大价值 // 递推公式 dp[i][j] = max(dp[i-1][j], dp[i-1][j-w(i)]+v(i)) // 初始化,背包容量为0初始化为0,物品0 初始化小于w(0)的背包价值为0. 大于初始化为v(0) // 遍历,先物品后背包 // 打印 var dp = make([][]int, len(weights)) for i := 0; i < len(dp); i++ { dp[i] = make([]int, n+1) } // dp[i][0] 初始化为0,dp[0][j] 看情况 for i := 0; i < len(dp); i++ { for j := 0; j < len(dp[0]); j++ { if j == 0 { dp[i][j] = 0 } else if i == 0 { if j >= weights[i] { dp[i][j] = value[i] } else { dp[i][j] = 0 } } else { var v1, v2 int v1 = dp[i-1][j] if j-weights[i] >= 0 { v2 = dp[i-1][j-weights[i]] + value[i] } fmt.Println(v1, v2) dp[i][j] = max(v1, v2) } } } fmt.Println(dp) }
copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
// pake // // @Description: // @param weights: 物品i对应重量 // @param value: 物品i对应价值 // @param n: 背包容量 // @return int func pake(weights, value []int, n int) { // dp 五部曲 // 确定dp数组以及下标的含义: dp[j] 代表容量为j的背包装物品能够获得的最大价值 // 递推公式 dp[j] = max(dp[j], dp[j-w(i)]+v(i)) // 初始化,背包容量为0初始化为0,其他也初始化为0 // 遍历,先物品后背包,但是背包要反序遍历,因为递推公式依赖的是上一层循环的前一个元素,如果在遍历过程中修改了上一层的之前元素,那么之后的递推就是错误的, 可能导致一个物品多次使用的情况, // 打印 var dp = make([]int, n+1) for i := 0; i < len(weights); i++ { for j := n; j > 0; j-- { var v int if j-weights[i] >= 0 { v = dp[j-weights[i]] + value[i] } dp[j] = max(dp[j], v) } } fmt.Println(dp) }

416 分割等和子集

copy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
func canPartition(nums []int) bool { // 本题主要难点在于,能否想到,通过将target = sum/2 ,并且填满target容量的背包从而转换成01背包问题 // 证明,01背包元素不重复,如果dp[target] == target, 使用了m个元素,和为target=sum/2,那么剩下元素和也为sum/2,从而出现两个子集和相同 // dp数组以及下标,dp[j] 表示容量j能装的最大价值,本题数组可以看作重量=价值 // 递推公式 dp[j] = max(dp[j], dp[j-w[j]]+v[j]) = max(dp[j], dp[j-nums[j]]+nums[j]) // 初始化 全部0 // 遍历顺序,外层物品正序,内层背包倒叙 // print var sum, target int for _, v := range nums { sum += v } if sum % 2 == 1 { // 和为奇数无法等量划分 return false } target = sum / 2 dp := make([]int, target + 1) for i:=0; i<len(nums); i++{ for j:=target; j>=nums[i]; j-- { //j>nums[i] 表示空间至少要比i所占用空间大,不然就无法放入,当然也可以在内部判断剪枝 dp[j] = max(dp[j], dp[j-nums[i]] + nums[i]) } } fmt.Println(dp) if dp[target] == target{ return true } return false } func max (i, j int )int { if i>j{ return i } return j }

本文作者:周公瑾55

本文链接:https://www.cnblogs.com/zhougongjin55/p/18369118

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

本文作者:周公瑾55

本文链接:https://www.cnblogs.com/zhougongjin55/p/18369118

posted @   周公瑾55  阅读(6)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.