Acwing:送礼物(双向DFS Python)

 题目链接🔗:171. 送礼物 - AcWing题库

分析:

看到题目数据范围 N最大取46 根据背包问题的思想 每件物品有取和不取两种情况 那么总的时间复杂度就是O(2^46) 那一定会超时了 所以我们考虑能不能使用双向DFS 即 我们先预处理出一半的数据 也就是dfs一下前N/2个物品能取到哪些小于W的总重量 然后再dfs剩下一半的数据 第二次dfs出的剩下N/2个物品能凑出的总重量 只需要看一下第一组数中能与该数凑出最接近且不大于W的数是多少即可 这里我们可以先讲第一组的数排序一下然后二分查找答案即可。

具体解释请看注释

import bisect
W,N = map(int,input().split())
weight = [0]
for i in range(N) :
    weight.append(int(input()))
total_weights = []
weight.sort(reverse=True) # 倒序排序加快搜索速度
    
ans = 0
K = N//2 + 2 # 前一半的数量
def dfs_1(now_depth,now_weight) :
    global total_weights
    if now_depth == K :
        total_weights.append(now_weight)
        return
    dfs_1(now_depth+1,now_weight) # 不选这个物品
    if now_weight + weight[now_depth] <= W :
        dfs_1(now_depth+1,now_weight+weight[now_depth]) # 选这个物品
        
def dfs_2(now_depth,now_weight) :
    global ans
    if now_depth > N :
        if W - now_weight in total_weights : # 如果前一组数中有刚好可以当前数凑出W的数
            ans = W
            return 
        else :
            if now_weight == 0 :
                return
            tmp = bisect.bisect_left(total_weights,W-now_weight)  # 二分查找 注意需要-1 因为bisect_left的含义是将当前数插入到total_weights中的位置,
            # 所以应该找上一个数才是比他小的最大数
            tmp -= 1
            ans = max(ans,total_weights[tmp] + now_weight) # 更新答案
            return
    dfs_2(now_depth+1,now_weight) # 含义同上
    if now_weight + weight[now_depth] <= W :
        dfs_2(now_depth+1,now_weight+weight[now_depth])
        
dfs_1(0,0)
total_weights = list(set(total_weights)) # 去重
total_weights.sort() # 排序,有序的序列才能使用二分查找
dfs_2(K,0)
print(ans)

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UCSD.KS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值