洛谷 P2392 kkksc03考前临时抱佛脚 python解析

kkksc03考前临时抱佛脚

日期:2023.9.24
题目地址:kkksc03考前临时抱佛脚


题目分析

最近新学了回溯和动态规划,刚好就借着这个题来巩固一下。
用了两个个方法逐步优化一下,回溯搜索 -> 动态规划。
这个题目要求四科花的时间最少,就是相当于单独处理每一科的时间最少。

  1. 回溯搜索
    这个其实就是有点像暴力枚举一样,考虑了所有答案,取最小的。也可以叫作深搜,这个方向就左脑和右脑两种,从左脑开始,先左后右,到头了就回到上一个状态,考虑了所有结果。题目数据量很小,但还是担心会不会超时。果然,超时了。只拿了90分。

回溯搜索提交结果

  1. 动态规划
    这个就可以看作01背包问题了,背包大小最大是 1200 容量,物品最多20个。
    理想情况:最优的时候无疑就是左右脑各为总时间的一半 s u m / 2 sum/2 sum/2 。那么,我们就想办法让其中一个脑子往这一半靠,那么另一个脑子便是结果了。
    这个解释一下,就是相当于,一个脑当背包耗时 v v v,那另一个脑的用时就是总用时减去前面那个脑的重量 s u m − v sum-v sumv。最终用时就是 m a x ( v , s u m − v ) = s u m − v max(v, sum-v)= sum-v max(v,sumv)=sumv。因为 v < = s u m / 2 v<=sum/2 v<=sum/2
    不出意外,快了很多。
    动态规划提交结果

代码

  1. 回溯搜索
"""
回溯搜索
"""

s_li = [int(i) for i in input().split()]

"""
x:当前搜索的元素为第几个; 
y:此时是第几科(总共4科);
left:记录左脑用时;
right:记录右脑用时;
minn:记录当前最小用时。
"""
def backsearch(x, y, left, right, minn): 
    # 当前科目的题目做完了, 记录最小时间。
    if x+1 > s_li[y]:
        # max(left, right) 
        # 选出最大值,因为左右脑只能同时在同一科目工作, 最大的即为当前科目的耗时。
        minn = min(minn, max(left, right))
        return minn
    
    # 先左脑
    left += a_li[x]
    minn = backsearch(x+1, y, left, right, minn)
    # 回溯
    left -= a_li[x]
    
    # 再右脑
    right += a_li[x]
    minn = backsearch(x+1, y, left, right, minn)
    right -= a_li[x]
    
    return minn

ans = 0
for i in range(4):
    left = 0
    right = 0
    minn = 2e7
    a_li = [int(i) for i in input().split()]
    ans += backsearch(0, i, left, right, minn)
    
print(ans)
  1. 动态规划
"""
动态规划
"""

s_li = [int(i) for i in input().split()]

ans = 0
for i in range(4):
    # 初始化
    # 这个数组用来记录在当前科目下,总耗时不超过 k 时,一个脑子的最大耗时之和
    dp = [0]*2501
    a_li = [int(i) for i in input().split()]
    summ = sum(a_li) # 总耗时
    for j in range(s_li[i]):
        for k in range(summ//2, a_li[j]-1, -1):
            # 让这个脑子的用时尽可能的接近summ//2。
            dp[k] = max(dp[k], dp[k-a_li[j]]+a_li[j])
    # 另一个脑子的耗时便是结果
    ans += summ - dp[summ//2]
print(ans)

这里还是解释一下动态规划的思想体现:

“”“
在每个 k 的位置,更新 dp[k] 的值。这里使用动态规划的思想,dp[k] 的值取两种情况中的最大值:

不选当前题目 j,即 dp[k] 保持不变。
选取当前题目 j,即 dp[k] 更新为 dp[k-a_li[j]] + a_li[j]。这表示当前总耗时 k 下,如果选择题目 j,那么这个脑的最大耗时之和就是 dp[k-a_li[j]](在不选题目 j 的基础上加上题目 j 的耗时 a_li[j])。
”“”

小结

当然,可能还有其他的优解,读者可以自己去试试呢。我也不知道我解释的清不清楚,有疑问欢迎评论交流。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值