一個講得特別細(luo)膩(suo)的動態規劃之入門

//我其實早就想寫一篇動態規劃的文章了,雖然我也很弱……我的思路會和市面上的一些輔導書不同,我直接從揹包問題入手,主要面對初學者,講的比較囉嗦,還會涉及很多優化供學有餘力者學習。一旦弄懂了這類比較典型也比較難的問題,動態規劃的能力會顯著提升。
文章裏可能會有紕漏,希望大家幫我指出,但是請不要嘴臭

目錄

  • 簡短的動態規劃思想入門
  • 0 - 1揹包
  • 完全揹包
  • 多重揹包
  • 混合揹包
  • 揹包問題的各種延伸
  • 區間動態規劃
    (有時間的話會繼續擴充樹上動歸等等,畢竟是學生狗)

動態規劃定義

沒用,想看自行百度(滑稽


一些基本知識和dp(動態規劃)的基本認識

- 最優化原理和無後效性原則

作爲一個弱省蒟蒻,我的粗鄙的理解就是「現在要乾的事對之前沒有影響而且是最好的」,這也是符合我們的認知規律的。比如說,我們小學時有接觸過一類題(當時虐的年幼的我死去活來)

小明的媽媽要看電視劇,所以小明必須艱苦創業自力更生(霧)。小明早上要幹許多事,比如燒水,開電腦luogu簽到,上廁所。燒水需要5分鐘,上廁所需要2小時(真實),開電腦需要1小時,怎樣安排用時最短?

首先,在生活中,現在做的事肯定不會影響過去(起碼暫時不會 ) ,同樣未來做的事也不會影響到現在,這就叫做無後效性原則

那麼什麼是最優化呢?比如說我們已經開始燒水,那我們現在應該幹什麼呢,很顯然是開電腦,這樣我們上完廁所後水也燒好了,電腦也開了(痔瘡也有了 )。這就是最優化原理,我們只要最好的。

- 記憶化搜索

表面高大上,但是很多人在做水題的時候早就基本掌握這個思想了。

N!即1 * 2 * 3 … * N,現在,我們求99!,100!,101!怎麼辦呢?

顯然(粗鄙之言),我們只需要算出99!,就不需要再從頭計算了,因爲100!即是99! * 100。

如果我要求的是1!,2!…N!呢,並且要求在全部計算完之後輸出答案?

顯然(逃),我們需要開一個a[101]數組,去保存答案最後輸出。這樣的話,問題就簡單了,我們求N!,只需要知道(N - 1)!,求(N - 1)!,只需要知道(N - 2)! ……以此類推,我們只需要知道1! = 1,我們便可以推出2!,進而推出3!……而不需要每次都從頭計算。我們將算出的1!,2!……存入a數組,不僅要作爲答案輸出,還要繼續使用它,就好像我們將1!……記下了一樣,因此叫記憶化。

記憶化搜索中的dp思想

首先,求N!的過程是滿足最優化和無後效性的,所以才能想到這道題可以用dp(雖然好像並沒有明確的選擇最優,但是我們由(N - 1)!得出N!時只有一個選擇—— *N,我們別無選擇♂時的唯一一個選擇,就可以認爲是最優的。

作爲讓OI選手頭疼的攔路虎,狀態設計和轉移方程無數次令我自閉。其實,只要做題時勤于思考,這種思維方式是可以逐步形成的。

上述問題我們僅用了一層循環便解決了問題(僅僅舉例,高精度等問題自己把控),既然說是dp,我們該怎樣設計狀態和書寫轉移方程呢?

在dp中,有種思想特別有用,這種思想叫做逆推(並不適用於所有題),這道題我們不妨逆推。

上文中,我們已設計好了狀態(即由1!求2!進而求3!……),大概是下面這個樣子的


進而狀態轉移方程也得到了:a[N] = a[N - 1] * N;

具體的代碼我希望大家自己實現,大部分OJ平臺也有相應題目,一個問題沒有細膩的思考是一無所獲的,千萬不要好高騖遠啊!