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

黃金問題

如今有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.送禮物一致,讀者可自行嘗試提交,驗證本身代碼的正確性。遍歷

相關文章
相關標籤/搜索