1. 程式人生 > >感性理解深搜和剪枝

感性理解深搜和剪枝

感性理解深搜和剪枝

上網看了一些部落格,感覺寫的不太清楚,這裡我清晰的來總結一下。

目錄(擺脫書籍,輕鬆理解)

感性理解深搜和剪枝

首先剪枝:

          1.什麼是“剪枝”

          2.剪枝的三大原則

                     (1).正確性

                     (2).準確性

                     (3).高效性

 其次深搜的優化技巧

           1.優化搜尋順序

           2.排除等效多餘

           3.可行性剪枝

           4.最優性剪枝

           5.記憶化

最後來一個小小的總結吧


首先剪枝:

1.什麼是“剪枝”

顧名思義,剪枝就是剪掉一下耗時的可以不要的東西,

舉個形象的例子吧:一棵樹,按照常理每一年都要剪掉一些枝條,為什麼呢?因為要給主體部分留足夠的營養,把這些浪費營養的枝條都剪掉,這就有了剪枝。同樣的,在c++當中,剪枝就是為了把那些浪費時間,可以跳過列舉的給去掉,從而做到最快最簡最優。

2.剪枝的三大原則

(1).正確性

這是最重要的,為什麼呢?我們剪枝是為了程式碼的優化性,如果剪枝出現了錯誤,把該留下的全部刪掉了,那麼這個剪枝再怎麼高階都沒有用了。
(正確性為剪枝的前提)

(2).準確性

可能會有疑問,準確和正確有怎麼區別?正確是指剪掉的枝是該剪的,準確性就是為了優化程式碼而儘可能的剪去不能同行正解的枝條,剪枝有了較高的準確性之後才能更快更準更優。(準確性為剪枝的核心)

(3).高效性

高效指的就是:改善判斷的準確性外,經常還需要提高判斷操作本身的時間效率。但是你想一下,如果我們改善了剪枝判斷的準確性,就不得不提高判斷操作的複雜度,這也就同時降低了剪枝判斷的時間效率。所以高效性就是我們剪枝最困難的一步,就是要解決這個矛盾,從而是程式碼變得高階。(高效性為剪枝的保障)

 其次深搜的優化技巧

 1.優化搜尋順序

我們在搜尋當中,難免會出現一些樹的各個層次、各個分支之間的順序不是固定的,而且也會有不同的形態,這個坑坑窪窪就會影響我們的搜尋,就想一條路,如果全都是坑,那麼必然會影響我們奔跑的速度,所以我們就要優化搜尋順序,使這棵樹的一些大層次可以是相似的,這樣就可以大大的優化我們的搜尋速度。(優化搜尋順序是技巧的前提,因為我們只有把路走直了,才可以進行更多的優化)

2.排除等效多餘

這個就很好理解了,就是說如果我們在搜尋的過程中,發現這棵樹有好幾個分枝都是等效的(相同的),那麼這個時候我們就只需要對其中的一條分枝執行搜尋。(排除等效多餘是技巧的偷懶,這一步可以大大減少時間)

3.可行性剪枝

其實就是一個靈活性的問題,為什麼這麼說呢?因為如果我們在搜尋的過程中,發現當前的這個分枝根本到不了我們遞迴的正規,也就是說走到了死衚衕,這個時候就要立即折返繞路,而不是走到路的盡頭發現是死衚衕才返回。

某些題目條件的範圍限制是一個區間,這時可行性剪枝也被稱為“上下界剪枝”(可行性剪枝是技巧的核心,為什麼呢?因為如果每一次都算到盡頭那一定超時,所以這個就是核心)

4.最優性剪枝

這個就更加好理解了,就是說如果我們後面搜尋到的比我們之前記錄過的最小值還要大的話,就停止搜尋,執行回溯。(最優性剪枝是技巧的保障,因為往往搜尋到後面就會越來越麻煩,所以這個最優性可以讓我們最快的確定最優解)

5.記憶化

記錄每個狀態的搜尋結果,在重複遍歷搜尋的時候直接檢索返回值。就好比我們在對圖進行深搜的時候,標記一個節點是否已經被訪問過。同時因為儲存了狀態,所以我們呼叫最優性剪枝的時候就會大大節省時間,這就是記憶化可以讓一個原本沒有記憶化是100多ms的程式碼變成一個10幾ms的程式碼。(記憶化是技巧的高階,用好陣列,靈活定義陣列的初始狀態)

最後來一個小小的總結吧

1.幾乎所有的搜尋都會用到可行性剪枝

2.在尋找最小值的時候,優先考慮最優性剪枝和記憶化,因為沒有最優化剪枝,十有八九都是超時的

3.部分搜尋要回溯,其實就是我們自己呼叫一個值的時候要標記使用,然後用完之後要歸零

4.有個小小的東西,dfs搜尋的函數千萬不要擔心定義的數太多,往往在一開始的時候定義多一點也沒關係,因為等你找到了正解之後可以進行技巧的修改,使得程式碼更加的簡單快速,做到三大原則