第九章 動態規划
1 動態規划——背包問題
公式:
練習
9.1 假設你還可偷另外一件商品——MP3播放器,它重1磅,價值1000美元。你要偷嗎?
要。在這種情況下,你可偷來MP3播放器和iPhone和吉他,總價值為4500美元
行的排列順序發生變化時結果如何?答案沒有變化。也就是說,各行的排列順序無關緊要。
可以逐行而不是逐列填充網格嗎?就這個問題而言,這沒有任何影響,但對於其他問題,可能有影響。
增加一件更小的商品將如何呢?你需要考慮的粒度更細,因此必須調整網格。
可以偷走商品的一部分嗎?答案是沒法處理。使用動態規划時,要么考慮拿走整件商品,要么考慮不拿,而沒法判斷該不該拿走商品的一部分。但是貪婪算法可以輕松處理!
2 旅行行程最大化
根據清單畫動態規划網格:
如何處理相互依賴的情況?
動態規划功能強大,它能夠解決子問題並使用這些答案來解決大問題。但僅當每個子問題都是離散的,即不依賴於其他子問題時,動態規划才管用。
計算最終的解時會涉及兩個以上的子背包嗎?
為獲得前述背包問題的最優解,可能需要偷兩件以上的商品。但根據動態規划算法的設計,最多只需合並兩個子背包,即根本不會涉及兩個以上的子背包。不過這些子背包可能又包含子背包。
最優解可能導致背包沒裝滿嗎?of course
練習
9.2 假設你要去野營。你有一個容量為6磅的背包,需要決定該攜帶下面的哪些東西。其中每樣東西都有相應的價值,價值越大意味着越重要:
水(重3磅,價值10);
書(重1磅,價值3)
食物(重2磅,價值9);
夾克(重2磅,價值5);
相機(重1磅,價值6)。
請問攜帶哪些東西時價值最高?用動態規划做唄,水,食物,相機
3 最長公共子串
動態規划的啟示:
①動態規划可幫助你在給定約束條件下找到最優解。
②在問題可分解為彼此獨立且離散的子問題時,就可使用動態規划來解決。
③每種動態規划解決方案都涉及網格。
④單元格中的值通常就是你要優化的值。
⑤每個單元格都是一個子問題,因此你應考慮如何將問題分成子問題,這有助於你找出網格的坐標軸。
舉個🌰:Alex輸入了hish,那他原本要輸入的是fish還是vista呢?
3.1 繪制網格
解決上面問題的網格應該怎么構建,要考慮下面幾點:
①單元格中的值是什么?在這個例子中,你要找出兩個單詞的最長公共子串,這就是你要計算的值。
②如何將這個問題划分為子問題?你可能需要比較子串:不是比較hish和fish,而是先比較his和fis。
③網格的坐標軸是什么?每個單元格都將包含這兩個子串的最長公共子串的長度。這也給你提供了線索,讓你覺坐標軸很可能是這兩個單詞。
因此,網格可能類似於下面這樣:
3.2 填充網格
填充時用什么公式呢?費曼算法(Feynman algorithm)步驟如下:(這怕不是再說廢話= =!廢慢算法?)
①將問題寫下來
②好好思考
③將答案寫下來
3.3 揭曉答案
查找單詞hish和vista的最長公共子串時,網格如下:
對於背包問題,最終答案總在最后的單元格中;但對於最長公共子串而言,答案是網格中最大的數字——不一定在最后的單元格中。
那么問題的答案出來了,hish和fish的最長公共子串包含三個字母,而hish和vista的最長公共子串包含兩個字母。因此Alex很可能原本要輸入的是fish。
3.4 最長公共子序列
假設Alex不小心輸入了fosh,他原本想輸入的是fish還是fort呢?我們使用最長公共子串公式來比較它們:
所以都為2,長度相同,但是fosh和fish更像。
這里應該比較最長公共子序列:兩個單詞中都有的序列包含的字母數。
3.5 最長公共子序列之解決方案
上圖的公式:
動態規划的實際應用:
①生物學家根據最長公共序列來確定DNA鏈的相似性,進而判斷度兩種動物或疾病有多相似。最長公共序列還被用來尋找多發性硬化症治療方案。
②你使用過諸如 git diff 等命令嗎?它們指出兩個文件的差異,也是使用動態規划實現的。
③前面討論了字符串的相似程度。編輯距離(levenshtein distance)指出了兩個字符串的相似程度,也是使用動態規划計算得到的。編輯距離算法的用途很多,從拼寫檢查到判斷用戶上傳的資料是否是盜版,都在其中。
④你使用過諸如Microsoft Word等具有斷字功能的應用程序嗎?它們如何確定在什么地方斷字以確保行長一致呢?使用動態規划!
練習
9.3 請繪制並填充用來計算blue和clues最長公共子串的網格。
4 小結
①需要在給定約束條件下優化某種指標時,動態規划很有用。
②問題可分解為離散子問題時,可使用動態規划來解決。
③每種動態規划解決方案都涉及網格。
④單元格中的值通常就是你要優化的值。
⑤每個單元格都是一個子問題,因此你需要考慮如何將問題分解為子問題。
⑥沒有放之四海皆准的計算動態規划解決方案的公式。