题解 | #购物单# Go 代码

购物单

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

这题倒霉就倒霉在我一开始没看清题目...金额后面的那个数字按照题意是表示接下来有几个物品, 我前面一直把这个理解成购买物品的个数限制

其实这个题就是个 dp 背包问题, 主要难点还是在题目的理解上, 首先你得排除附件, 先只关注主件, dp[i][j] 的定义就是取到 i 这个主件时, 有 j 这么多的钱的情况下, 能拥有的最大价值是多少

然后再来处理附件问题, i 这个主件在 j 金额下, 只有两种情况, j 金额不够 i 主件的价格, 所以该主件无法购买, 所以 dp[i][j] = dp[i-1][j], 也就是取到前一个主件不取当前主件的时候(金额不变)

当 j > i 主件的价格, 选择根据题意有以下几种, 只取主件, 取主件和附件1, 取主件和附件2, 取主件和附件1+附件2, 然后计算每种情况的最大价值即可, 实际上相比于背包问题原题, 这题的改动就是在这里而已

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

func main() {
    var budget, limit int // 这个定义的 limit 实际上没用, 最开始理解错就在这里
    fmt.Scan(&budget, &limit)
    items := [][]int{}  // 代表主件
    attach := map[int][][]int{}  // 代表附件, 用主件的物品序号取
    no := 1  // 物品序号

    for {
        var price, weight, q int
        n, _ := fmt.Scan(&price, &weight, &q)
        if n == 0 {
            break
        }

        if q == 0 {
		  // 注意这里第三个元素不再是 q 而是 序号, 因为后面需要用主件序号从 attach 中取出它的附件
            items = append(items, []int{price, weight, no})
        } else {
            if attach[q] == nil {
                attach[q] = [][]int{}
            }
            attach[q] = append(attach[q], []int{price, weight, q})
        }
        no++
    }

  // 因为需要观察取到前一个主件的情况(dp[i-1]), 所以 dp 的长度是主件数 +1
    dp := make([][]int, len(items)+1)
    for i := 0; i <= len(items); i++ {
        dp[i] = make([]int, budget+1)
    }

    for i := 1; i <= len(items); i++ {
        for j := 0; j <= budget; j++ {
            if j - items[i-1][0] < 0 {
			  // 说明 这个金额没法购买当前这个组件
                dp[i][j] = dp[i-1][j]
            } else {
			  // 当前金额已经起码足够购买主件本身
			  // cost1,2,3,4 分别代表只买主件的花费, 买主件+附件1 的花费, 买主件+附件2 的花费, 买主件+附件1+附件2 的花费
			  // value代表对应cost的价值
                var cost1, cost2, cost3, cost4 int
                var value1, value2, value3, value4 int

                cost1 = items[i-1][0]
                value1 = items[i-1][0] * items[i-1][1]

                a := attach[items[i-1][2]]
                if a != nil {
				  // 如果这个主件是有配件的, 根据配件数量填入 cost2 ~ 4 的值
				  // 不要在意这一堆 index 的可读性, 我也懒得改了...能看懂就行
                    if len(attach[items[i-1][2]]) > 0 {
                        cost2 = cost1 + attach[items[i-1][2]][0][0]
                        value2 = value1 + attach[items[i-1][2]][0][0] * attach[items[i-1][2]][0][1]
                    }
                    if len(attach[items[i-1][2]]) > 1 {
                        cost3 = cost1 + attach[items[i-1][2]][1][0]
                        value3 = value1 + attach[items[i-1][2]][1][0] * attach[items[i-1][2]][1][1]

                        cost4 = cost3 + cost2 - cost1
                        value4 = value3 + value2 - value1
                    }
                }
				
			  // 只买主件的时候 dp 取值
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-cost1]+value1)
                if j - cost2 >= 0 {
				  // 如果负担得起 cost2, 比较一下最值
                    dp[i][j] = max(dp[i][j], dp[i-1][j-cost2]+value2)
                }
                if j - cost3 >= 0 {
                    dp[i][j] = max(dp[i][j], dp[i-1][j-cost3]+value3)
                }
                if j - cost4 >= 0 {
                    dp[i][j] = max(dp[i][j], dp[i-1][j-cost4]+value4)
                }
            }
        }
    }

    fmt.Println(dp[len(items)][budget])
}

全部评论

相关推荐

冲芭芭拉鸭:你这图还挺新,偷了。
投递美团等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务