[搜索算法系列] —— 折半搜索

黄金问题

如今有n块黄金,每块黄金的质量为w[i],小明能够一次性搬运质量不超过m的物体,问小明一次至多能运走多少质量的黄金?

对于该问题,阅读过我以前讲过的深度优先搜索应该不难写出以下代码。python

def dfs(cur, total, status = set()):
    for i in range(cur, n):
        if total + w[i] > m:
            continue
        status.add(total + w[i])
        dfs(i+1, total + w[i])
    return status

对于w = [1,8,6],m = 10的数据,能够获得status = {1,8,6,9,7},也就是w可以组合出的不超过m的全部值,取其最大值即为该问题的答案。post

可是该解法的时间复杂度过高了,为n!(这里还与m值有关,要真有这么大都别玩了),其实这里能够动态规划,咱们如何应对更大n值的状况?code

对于规模为10的状况,其复杂度在400w,而对于规模为5的状况,其复杂度在100,也就是说若是咱们可以把一个规模为10的问题分解成两个规模为5的问题,那么时间复杂度只须要100 + 100 = 200。速度较以前提高了2万倍。get

那么咱们如何经过两个规模为5的解得出规模为10的解呢?io

def solution(n, m, w):
    def dfs(cur, end, total = 0, status = set()):
        for i in range(cur, end):
            if total + w[i] > m:
                continue
            status.add(total + w[i])
            dfs(i+1, end, total + w[i])
        return status
    
    ans1 = sorted(list(dfs(0, n//2)))
    ans2 = sorted(list(dfs(n//2, n)))
    ans  = max(ans1)
    for i in ans2:
        t = binary_search_last_equal_or_lower(m-i, ans1)
        ans = max(ans, t+i)
    return ans

上述代码中,咱们遍历ans2列表,在ans1寻找最大的且与i相加不超过m的值(反过来也行),并在遍历的过程当中动态更新ans的值,遍历结束,ans即咱们想要的答案。ast

对于最终的ans,有以下三种可能。class

  1. ans1[i] + ans2[j]
  2. max(ans1)
  3. max(ans2)

其中状况1在遍历时完成,状况2在ans赋初值时完成,状况3在ans1没有值能够与m-i结对时完成(这时候二分查找返回0值)。搜索

本文示例题目与acwing 171.送礼物一致,读者可自行尝试提交,验证本身代码的正确性。遍历

相关文章
相关标签/搜索