對01揹包問題的思考

經過我的一通研究, 動態規劃已經被我分成兩大類,即分階段決策問題以及枚舉問題.在枚舉界,深度優先搜索可謂明星算法,不僅如此,它還能跨界發展,因爲在動態規劃界,DFS天然的樹狀路徑總讓人覺得與DP的最優子結構有着曖昧不清的關係.如果我們能用DFS的思想去分析問題,然後最終打開一扇DP的大門就好了.
然而,事實證明上述想法裏YY的成分多一些,可是DFS和DP確實存在着某種神祕關聯,下面對01揹包問題的分析就是鐵證.

還沒貼圖,會補上的…

揹包問題

先把問題描述清楚:

揹包最大負重爲5,現有三個物品,重量是(2,3,4).相應地,三個物品的價值爲(10,15,20).現在要從三個物品中選擇若干件裝入揹包.請問:在不超出揹包負重上限的前提下,怎樣選取才能使包中物品總價值最大?

第0個思路

經觀察,應選擇前兩個物品.

好好好滿分.現在揹包容量是65536,有4096個物品可以選,麻煩再來觀察一下?
別跟我提貪心,我要是再相信貪心我就是DOG.

第一個思路

不扯淡了,其實第一個想到,也是最直觀的策略,一定是枚舉:

方案 最終重量 最終價值
(0,0,0) 0 0
(0,0,1) 4 20
(1,1,1) 8 45

其中(0,0,0)表示”不選第一個,不選第二個,不選第三個”.

好好好,又是滿分.現在揹包容量是65536…

怎麼枚舉?

仔細分析上述枚舉的過程:

  • 首先面對0號物品,我們可以選擇也可以不選擇;
  • 如果我們選擇0號物品:
    • 現在我們面對1號物品,我們可以選擇也可以不選擇;
    • 如果我們選擇1號物品:
      • 現在我們面對2號物品,我們可以選擇也可以不選擇:
      • 如果我們選擇2號物品:
        • 由於已經選擇了1號和2號,揹包已經裝滿了,不能選擇
      • 如果我們不選擇2號物品:
        • 我們最終的選擇是(1,1,0),總重量是5,總價值是25
    • 如果我們不選擇1號物品:
  • 如果我們不選擇0號物品

算了,直接上圖吧:

更精確的表述

當處理2號物品的時候,我們需要的參數,如果揹包的當前重量,已擁有的總價值等等,通通需要從樹根開始計算.這肯定是不對的,正確的遍歷方法是隨身攜帶參數:

其中,節點(0,1,5)所表述的問題是

揹包最大負重爲5,可選物品爲(0,1,2).假設我一定會選擇0號物品.請問在滿足題設的前提下,怎樣選取剩餘物品才能使揹包中的價值最大?

整個問題的最終答案取決於森林中每個樹的根.最終取決於森林中所有的葉.

動態規劃

能用動態規劃解決問題嗎?回想一下,動態規劃的大門前永遠都站着個巨大的門神:重疊子問題,最優子結構.
最優子結構已經清楚地寫到遞歸樹的臉上去了.
然而重疊子問題在哪兒?上述遞歸樹有相同的節點嗎?

掘地三尺

找不到重疊子問題?那就往下挖.

回到遞歸樹(森林)上.現在將注意力集中到最後一層.最後一層有兩類節點,一類節點是(2,0,X),另一類是(2,1,X).各佔一半.我們以(2,0,X)爲例.(爲了方便敘述,”第2層的節點”代表的是”森林中所有高度爲2的節點”).

因爲X是揹包的上限,所以X非負數.又從上述分析知道,隨着高度增加,X可能減少但絕不增加.再考慮到X的初始值爲5.所以X最多有6個不同取值.

所以,最後一排最多有12不同的節點.

回頭再看,上述分析過程中並沒有用到”最後一層”這個條件,我們可以把分析應用到”第一層”或者”第二層”,這隻會改變一些無關緊要的文字描述,分析過程完全不變,因此結論也完全不變.所以我們可以把結論中的”最後一層”去掉,這樣結論表述爲:

任意一層最多有12個不同節點.

乍一看是廢話,因爲森林只有3層,每層分別只有2,4,8個節點,肯定小於12.其實恰恰相反,這是個很重要的結論.

我們只要增加一個物品,比如(編號:3,重量:5,價值30),上述遞歸樹的高度就會變成4.如果森林有第4層,它將有16個節點,由剛纔的分析可以知道,這16個節點裏面最多有12個不同的節點.又因爲每個節點對應一個子問題,因此第4層裏出現的16個子問題中,最多隻有12個互不相同的子問題,即至少有4個子問題是重複的.

同理,如果森林有5層,那麼第5層32個子問題裏至少有20個子問題是重複的.
如果森林有6層…

重疊子問題:KAO,這都被找到了,真是R了G了.

複雜度

於是我們可以愉快地使用動態規劃了.

等等,作爲一個嚴謹的學者(別笑),我們先來分析一下複雜度吧.

現在一般化我們的問題,假設我們有N個物品,揹包負重上限是M,那麼揹包問題複雜度的兩個上限分析如下.

算法的第一個複雜度上限是O(2^N).

這個上限來自於深度優先搜索.並且這個上限並沒有什麼存在感,也就是說這個結論告訴我們無論算法多慢你都不比驚訝.

我們來分析算法的另一個上限.
首先每個物品在遞歸樹上佔一層.
其次,考慮到重疊子問題,以及上述一通亂七八糟的分析,我們知道每層最多有(M+1)個不同子問題.
於是我們可以輕易得出另一個上限:

O(N*M)是動態規劃解決揹包問題的第二個複雜度上限

這樣一來,最終結論就是:

動態規劃解決01揹包問題的複雜度是O(2^N)和O(N*M)中較小的那個.其中N是物品個數,M是揹包負重上限.

什麼?你說揹包上限是65536,物品有4096個?那也纔不到3億次計算而已.

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