經典算法精講精練之回溯法求解0-1揹包問題

       最近來一波基礎算法吧,掌握基礎原理方可行走天下。回溯法本質是用來搜索問題的解,典型地就是使用深度優先搜索,搜索路徑一般沿樹形結構進行,在搜索過程中,首先會判斷所搜索的樹結點是否包含問題的解,如果肯定不包含,則不再搜索以該結點爲根的樹結點,而向其祖先結點回溯;否則進入該子樹,繼續按深度優先策略搜索。

        可能這麼說不是很容易懂,咱們來的實例吧,那就是經典的0-1揹包問題,關於這一問題後邊很多算法都會涉及到,咱們一點點深入~

         我們還是使用典型的三揹包爲例,問題描述如下:設有三個揹包,其重量分別爲:16,15, 15;價值分別爲: 45,25,25;請選擇揹包,使其重量不超過30,但價值最大

         可以看出我們的約束條件爲總重量不超過30,目標是價值最大,那我們就可以使用回溯法的思想來求解:

         每個揹包都可以被選擇中或者不選,理論上如果不加任何限制的話一共有八種可能(2×2×2),但我們在搜索的過程中要時刻注意總重量不可超過30 ,在這個基礎上使其總價值最大,於是我們可以從第一個揹包開始,先選中它,其重量是16,小於30,沒有問題,然後在選擇第二個揹包,其重量爲15,二者總重量爲31,超過30,所以不能選擇第二個揹包,同理第三個揹包也不能選,也就是說在選中第一個揹包的前提下,另外兩個揹包就都不能再選了,這是八種理論可能情況中的一種;以此類推,不選第一個揹包,在此基礎上選擇第二個揹包,總重量爲15,沒有問題,再選第三個,此時總重量爲30,也沒有問題;對照這兩種情況,前者總價值爲45,後者總價值爲50,當然,我們以上帝視角可以看出最大價值也就是50,但落實到具體的算法該如何全方位多角度深層次地解決這一問題呢?

          我們來看一個完全二叉樹結構圖:

        對於上述的揹包問題,在此二叉樹結構中可以簡單地理解爲:從A出發,往左子樹方向走說明選中了A,往右子樹方向走說明沒有選中A,即“左選右不選”,落實到上圖中就是1代表選中0代表未選中;我們上邊說道的第一種情況,即只選中第一個揹包的情況對應上圖的A->B->E->K;那這裏有朋友可能會問了爲啥二叉樹會有四層,不是一共三個揹包嘛,對的,因爲我們每一層所代表的揹包選與不選都得由下一層所決定,比如節點E代表第三個揹包,如果我們走到K就說明不選E,反之,若走到J則說明選中了E,因此三個揹包我們需要四層完全二叉樹,同理,若有N個揹包則需要N+1層。

        當我們的搜索路徑到達K後,得到了一組值,即總重量爲16,總價值爲45,此時,由於已經到了樹的葉子結點,因此需要回溯直到根,再繼續進行後續的搜索,在後續搜索過程中,一方面要進行結點的判斷,另一方面,一旦得到了一個合符要求的價值,則與前一次搜索所得到的結果進行比較,如果比前一次搜索得到的值大,則取代,反之,繼續搜索直到整個樹搜索結束所得到的最大值即爲問題的解。

       總的來說,上述的求解過程在程序實現過程中可以這樣來理解:我們把二叉樹的每一層看成是某一個物品。當我們選擇物品時總是從第一個物品開始進行選擇,可能選,也可能不選。如果選中,則從二叉樹的左邊子樹開始搜索,如果未選中,則從二叉樹的右邊子樹開始搜索。以此類推即可~  

       如果將每個物品的重量對應每一層的一個節點,在每次選擇每一個物品時進行重量的判斷,並記錄權值,則可決定是否應該繼續搜索下一層的子樹。      

       如果設物品的重量存放在W數組中, W[i]爲第i個物品的重量,P[i]表示第i個物品的價值。C表示揹包能夠承受的最大重量。cw表示當前物品的重量,cp表示當前物品的價值(稍微記憶一下這幾個符號量的意義)。在選中情況下(即搜索左子樹)執行下面的操作:      

( 1 )首先判斷加上該物品重量後是否滿足最大重量不超過C的要求,如果不超過,則:       cw+=w[i];       cp+=p[i];   反之則搜索右子樹;   

( 2 )繼續搜索下一層,執行相同的操作;       

( 3 )當搜索到最後一層時,顯然可得到從根到該結點所選擇的所有物品的價值,如果該價值大於前一次得到的最大價值,則替代前一次的價值,反之,則不取代;     

( 4 )  退回到上一層,即其雙親結點所在的一層,顯然此時應執行:        cw-=w[i];        cp-=p[i];        

執行上述語句的目的在於爲訪問右子樹做準備。在訪問右子樹時,顯然不需要計算其重量和價值,因爲右子樹表示未選中該物品

      最後這幾步是我在一些資料中看到的...總感覺有問題,嘗試做了一些修改,還是有些彆扭,其實大家也可以理解,算法這東西變幻莫測,再基本的原理也可以有很多表現形式,可以進一步優化,我們不要以上帝視角看待這個過程,這樣會想當然地人爲進行條件約束;

後續算法會繼續優化,共同進步吧~~~~~~~~

本篇博文主要以文字爲主,可能看起來很迷,但對於算法大家一定要沉下心來去思考,這樣才能理解其原理,在此基礎上更進一步,優化算法,使其更加完美^^

如果本篇內容對你有一點點幫助,請點個贊或者收藏關注一下,讓我們一起努力

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章