動態規劃(Dynamic Programming, DP)
Dynamic的意思是動態的,而Programming則是以表格紀錄,所以DP其實就是以變動的表格來求解。
DP的應用很廣、變化很多,在程式競賽中常常遇到這類題目,而且DP有許多困難而精妙的(變態)優化方法,很多題目都需要花時間好好體會,所以此章只會先介紹一些典型的例題,後續的變化及優化方法將在進階動態規劃討論。
動態規劃和分治法相同,都是將問題分成子問題,再將子問題的解合併成最後的解,設計DP都是從尋找遞迴式開始,大致可分為三步驟。
動態規劃其實和遞迴枚舉類似,但重要的是動態規劃以表格將算過的數據紀錄下來,藉此大幅優化執行時間,這裡舉個費式數列的例子:
如果依照遞迴的想法,可快速寫出下列程式:
這程式可以跑,只要不輸入太大的數字,因為這遞迴函式會一個呼叫兩個,兩個呼叫四個,複雜度接近2的N次方。
但是我們真的需要這麼多的運算嗎?
觀察上圖之例子可知,我們其實重複執行了需多運算,如果能將每次運算的值都處存下來,便可節省許多的運算時間,這時我們可以將程式改寫如下。
透過一個dp[]陣列將運算過後的值存起來,並以-1來表示此數值還未計算過,但透過觀察可發現第n項的值是由n-1項和n-2項所構成的,那麼就可以用一個for迴圈由小到大計算數值來求第n項的值,進而縮減成下列程式碼:
那麼,在了解DP的基礎概念後,就能進入一系列的例題了。
題目連結:Frog1
思路:這題最主要的思路定義一狀態dp(i)為走到第i格時
程式碼:
題目連結:Frog2
思路:
程式碼:
APCS與競賽入門