CSP 何以包邮

题目

http://118.190.20.162/view.page?gpid=T152

思路

  1. 暴力枚举所有情况,能过70%;
  2. 回溯+剪枝,能过70%。应该还可以有其他优化,我的只过70.
  3. 类比背包问题 动态规划。这个需要反向思考。
    如一个例子:
    books: 20 30 60 60 90 计算得到所有数的和 sum:260 limit: 100
    目的是找到一个组合的和是 超过limit的最小值,那么反过来就是,找到一个组合的和是 不超过sum-limit的最大值
    这里可以转化为,找到一个组合的和是不超过 sum-limit=160的最大值,也就相当于背包问题中,限制了背包容量,求这个容量下能获得的最大价值。
    值得注意的是,背包问题中每个物品都有容量和价值两个属性,目的是最大化价值。然而,上面转化后只有一个容量属性,没有价值属性,目的是最大化容量。那么,容量就视为价值。
    就上面例子:
    容量160,可以选60 90 这个组合,容量150是不超过160的最大容量,同时也是要找的‘最大价值’。

代码

n, limit = map(int, input().split())
nums = [0] * (n+1)
sum = 0
for i in range(1, n+1):
    nums[i] = int(input())
    sum += nums[i]
'''
目的:用nums中的数组合 超过limit的最小值 转换为 不超过 sum - limit 的最大值,看作背包问题
将 sum - limit 作为背包容量,求这个容量下最大价值 
如:20 30 60 60 90 sum=260, limit = 100, V = sum - limit = 160
用容量为160的背包,找价值最大的组合(隐含了,将价值视作和物品容量等值)
'''
V = sum - limit 
# initialize dp : (n + 1) * ( V + 1)
dp = [[0]*(V+1) for i in range(n+1)]

# dp: dp[i][j] for max value when choosing from top i objects
for i in range(1, n+1):
    for j in range(1, V+1):
        # check if nums[i] can be choosed
        if j < nums[i]:
            dp[i][j] = dp[i-1][j]
        else:
            dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i]] + nums[i])
print(sum - dp[n][V])

总结

  1. 将超过limit的最小值转化为不超过sum-limit的最大值,从而转换为背包问题,逆向思维,转化思想。
  2. 根据问题的目的,这里需要将容量和价值看作等价的。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值