1. 程式人生 > >動態規劃的思考(三)

動態規劃的思考(三)

from [http://blog.csdn.net/thisinnocence]

1 一個問題:換零錢方式的統計

SICP 第一章 1.2.2 樹形遞迴中,有這麼一問題:給了半美元,四分之一美元,10美分,5美分和1美分的硬幣,將1美元換成零錢,一共有多少種不同方式?更一般的問題是,給定了任意數量的現金,我們能寫一個程式,計算出所有換零錢方式的種數嗎?

2 動態規劃的基本模型

動態規劃(Dynamic programming,DP),是研究一類最優化問題的方法,通過把原問題分解為相對簡單的子問題的方式求解複雜問題。動態規劃處理的也就是是多階段決策最優化問題,這一類問題可將過程分成若干個互相聯絡的階段,在每一階段都作出決策,從而使整個過程達到最好的結果。因此各個階段決策的選取不能任意確定,它依賴於當前面臨的狀態,又影響以後的發展。當各個階段決策確定後,就組成一個決策序列,從而也就確定了整個過程的一條活動路線。這種把一個問題看做是一個前後關聯具有鏈狀結構的多階段過程稱為多階段決策過程。動態規劃著名的應用例項有:求解最短路徑問題,揹包問題,專案管理,網路流優化等。動態規劃的基本模型如下:
  1. 確定問題的決策物件
  2. 對決策過程劃分階段
  3. 對各階段確定狀態變數
  4. 根據狀態變數確定費用函式和目標函式
  5. 建立各階段狀態變數的轉移過程,確定狀態轉移方程

3 使用動態規劃的一般前提

3.1 滿足動態規劃的最優化原理

作為整個過程的最優策略具有如下性質:無論過去的狀態和決策如何,對前面的決策所形成的當前狀態而言,餘下的諸決策必須構成最優策略。

通俗理解就是子問題的區域性最優將導致整個問題的全域性最優,即問題具有最優子結構的性質,也就是說一個問題的最優解只取決於其子問題的最優解,非最優解對問題的求解沒有影響。

3.2 滿足動態規劃的無後效性原則

所謂無後效性原則,指的是這樣一種性質:某階段的狀態一旦確定,則此後過程的演變不再受此前各狀態及決策的影響。也就是說,“未來與過去無關”,當前的狀態是此前歷史的一個完整總結,此前的歷史只能通過當前的狀態去影響過程未來的演變。

具體地說,如果一個問題被劃分各個階段之後,階段 I 中的狀態只能由階段 I+1 中的狀態通過狀態轉移方程得來,與其他狀態沒有關係,特別是與未發生的狀態沒有關係,這就是無後效性。從圖論的角度去考慮,如果把這個問題中的狀態定義成圖中的頂點,兩個狀態之間的轉移定義為邊,轉移過程中的權值增量定義為邊的權值,則構成一個有向無環加權圖,因此,這個圖可以進行“拓撲排序”,至少可以按他們拓撲排序的順序去劃分階段。

4 動態規劃設計方法

4.1 一般方法

一般由初始狀態開始,通過對中間階段決策的選擇,達到結束狀態。這些決策形成了一個決策序列,同時確定了完成整個過程的一條活動路線。步驟為:
  1. 劃分階段:按照問題的時間或空間特徵,把問題分為若干個階段。在劃分階段時,注意劃分後的階段一定要是有序的或者是可排序的,否則問題就無法求解。
  2. 確定狀態和狀態變數:將問題發展到各個階段時所處於的各種客觀情況用不同的狀態表示出來。當然,狀態的選擇要滿足無後效性。
  3. 確定決策並寫出狀態轉移方程:因為決策和狀態轉移有著天然的聯絡,狀態轉移就是根據上一階段的狀態和決策來匯出本階段的狀態。所以如果確定了決策,狀態轉移方程也就可寫出。但事實上常常是反過來做,根據相鄰兩段各狀態之間的關係來確定決策。
  4. 尋找邊界條件:給出的狀態轉移方程是一個遞推式,需要一個遞推的終止條件或邊界條件。
  5. 程式設計實現:動態規劃的主要難點在於理論上的設計,一旦設計完成,實現部分就會非常簡單。

4.2 逆向推導

逆向思維法是指從問題目標狀態出發倒推回初始狀態或邊界狀態的思維方法。如果原問題可以分解成幾個本質相同、規模較小的問題,很自然就會聯想到從逆向思維的角度尋求問題的解決。動態規劃與分治法最大的不同在於分解出來的各個子問題的性質不同:
  • 分治法要求各個子問題是獨立的(即不包含公共的子問題),因此一旦遞迴地求出各個子問題的解後,便可自下而上地將子問題的解合併成原問題的解。如果各子問題是不獨立的,那麼分治法就要做許多不必要的工作,重複地解公共的子問題。
  • 動態規劃與分治法的不同之處在於動態規劃允許這些子問題不獨立(即各子問題可包含公共的子問題),它對每個子問題只解一次,並將結果儲存起來,避免每次碰到時都要重複計算。這就是動態規劃高效的一個原因。
動態規劃的逆向推導步驟:
  1. 分析最優值的結構,刻畫其結構特徵;
  2. 遞迴地定義最優值;
  3. 按自底向上或自頂向下記憶化的方式計算最優值;

4.3 正向推導

正向思維法是指從初始狀態或邊界狀態出發,利用某種規則不斷到達新的狀態,直到問題目標狀態的方法。動態規劃的正向思維法,正是從已知最優值的初始狀態或邊界狀態開始,按照一定的次序遍歷整個狀態空間,遞推出每個狀態所對應問題的最優值。
正向思維法中,不再區分原問題和子問題,將動態規劃的過程看成是從狀態到狀態的轉移。將所有的狀態構造出一個狀態空間,並在狀態空間中設想一個狀態網路,若對兩個狀態i,j,存在決策變數di使t(i,di)=j,則向狀態網路新增有向邊。給定己知最優值的初始狀態或邊界狀態,可以沿著有向邊推廣到未知最優值的新狀態,利用狀態轉移方程得到新狀態的狀態變數的最優值。我們可以用這種方式遍歷整個狀態空間,得到每個狀態的狀態變數的最優值。
動態規劃的正向推導步驟:
  1. 構造狀態網路;
  2. 根據狀態轉移關係和狀態轉移方程建立最優值的遞推計算式:
  3. 按階段的先後次序計算每個狀態的最優值;

動態規劃需要按階段遍歷整個狀態空間,因此動態規劃的效率取決於狀態空間的大小和計算每個狀態最優值的開銷:如果狀態空間的大小是多項式的,那麼應用動態規劃的演算法就是多項式時間的;如果狀態空間的大小是指數的,那麼應用動態規劃的演算法也是指數時間的。因此,找一個好的狀態劃分對動態規劃的效率是至關重要的。

相關推薦

動態規劃專題——數位DP

前言 數位DPDPDP 真的是最噁心的DPDPDP。 簡介 看到那種給你兩個數,讓你求這兩個數之間符合條件的數的個數,且這兩個數非常大,這樣的題目一般就是 數位DPDPDP 題。 數位DPDPDP一般

動態規劃思考

from [http://blog.csdn.net/thisinnocence] 1 一個問題:換零錢方式的統計 SICP 第一章 1.2.2 樹形遞迴中,有這麼一問題:給了半美元,四分之一美元,10美分,5美分和1美分的硬幣,將1美元換成零錢,一共有多少種不同方式?

動態規劃入門

spa turn color and uil ott c++ erro 大數字 2017-09-01 11:29:43 writer:pprp 看sprout臺灣大學acm教學視頻的第一部分: 裏邊涉及到四道小例題 感覺很好就拿來寫了寫: 題意還有代碼說明都在代碼中: 1、

spring cloud實戰與思考 微服務之間通過fiegn上傳一組文件

ets inf str ceo iter protected let pan ins 需求場景:   用戶調用微服務1的接口上傳一組圖片和對應的描述信息。微服務1處理後,再將這組圖片上傳給微服務2進行處理。各個微服務能區分開不同的圖片進行不同處理。   上一篇博客已經討

動態規劃專題——斜率優化DP

前言 斜率優化\(DP\)是難倒我很久的一個演算法,我花了很長時間都難以理解。後來,經過無數次的研究加以對一些例題的理解,總算啃下了這根硬骨頭。 基本式子 斜率優化\(DP\)的式子略有些複雜,大致可以表示成這樣: \[f_i=min_{j=1}^{i-1}(A(j)-B(j)*S(i)+C(i)

LeetCode-動態規劃總結

最長遞增子序列 已知一個序列 {S1, S2,…,Sn},取出若干陣列成新的序列 {Si1, Si2,…, Sim},其中 i1、i2 … im 保持遞增,即新序列中各個數仍然保持原數列中的先後順序,稱新序列為原序列的一個 子序列 。 如果在子序列中,當下標 ix > iy

LeetCode-動態規劃總結

動態規劃 遞迴和動態規劃都是將原問題拆成多個子問題然後求解,他們之間最本質的區別是,動態規劃儲存了子問題的解,避免重複計算。 斐波那契數列 爬樓梯 70. Climbing Stairs (Easy) 題目描述:有 N 階樓梯,每次可以上一階或者兩階,求有多少種上樓梯

redis原始碼分析與思考——字典中鍵的兩種hash演算法

      在Redis字典中,得到鍵的hash值顯得尤為重要,因為這個不僅關乎到是否字典能做到負載均衡,以及在效能上優勢是否突出,一個良好的hash演算法在此時就能發揮出巨大的作用。而一個良好的has

動態規劃專題——樹形DP

前言 DPDPDP這東西真的是博大精深啊… 簡介 樹形DPDPDP,顧名思義,就是在樹上操作的DPDPDP,一般可以用fif_ifi​表示以編號為iii的節點為根的子樹中的最優解。 轉移的時候一般都將

Unity動態編輯Terrain 自定義筆刷

**** 程式碼我已經上傳到了我的Github上,需要的話可以直接去下載https://github.com/xdedzl/xdedzl,裡面有一個TerrainModilfyDemo的場景,我做了一個簡單的UI用來測試,工程版本是2018.3。注意編譯環境需要是.net4.x,用3.5會報錯。

百度大腦人臉識別深度驗證與思考之顏值識別

環境 win7 32位 VisualStudio2017 python3.6.3 opencv3.3.1 pyQt5.9 baidu-AIP 1.6.9.0 特別宣告 所有圖片均來自網路

動態規劃演算法---

摘自網路 題目: 國王和金礦 有一個國家發現了5座金礦,每座金礦的黃金儲量不同,需要參與挖掘的工人數也不同。參與挖礦工人的總數是10人。每座金礦要麼全挖,要麼不挖,不能派出一半人挖取一半金礦。要求用程式求解出,要想得到儘可能多的黃金,應該選擇挖取哪幾座金礦?

動態規劃演算法---

摘自網路: ———————————— 題目: 有一座高度是10級臺階的樓梯,從下往上走,每跨一步只能向上1級或者2級臺階。要求用程式來求出一共有多少種走法。 比如,每次走1級臺階,一共走10步,這是其中一種走法。我們可以簡寫成 1,1,1

關於大型網站技術演進的思考--儲存的瓶頸3

  儲存的瓶頸寫到現在就要進入到深水區了,如果我們所做的網站已經到了做資料庫垂直拆分和水平拆分的階段,那麼此時我們所面臨的技術難度的挑戰也會大大增強。   這裡我們先回顧下資料庫的垂直拆分和水平拆分的定義:   垂直拆分:把一個數據庫中不同業務單元的資料分到不同的資料庫裡。   水平拆分:是根據一定的規

關於大型網站技術演進的思考:儲存的瓶頸3

儲存的瓶頸寫到現在就要進入到深水區了,如果我們所做的網站已經到了做資料庫垂直拆分和水平拆分的階段,那麼此時我們所面臨的技術難度的挑戰也會大大增強。 這裡我們先回顧下資料庫的垂直拆分和水平拆分的定義: 垂直拆分:把一個數據庫中不同業務單元的資料分到不同的資料庫裡。

Python開發動態網頁基礎

from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is no

學習動態規劃DP——DAG模型

之前初學了一點關於動態規劃的知識,但沒有系統的學習,最近在空閒時間根據紫書(演算法競賽入門經典)開始了比較有計劃的學習,先寫下這篇部落格,作為筆記。 一、我對動態規劃的看法。 動態規劃,即是把原問題劃分為各個規模更小的問題去解決,原問題的最優解包括了

動態規劃第五講——leetcode上的題目動態規劃彙總

本節,我們將對leetcode上有關DP問題的題目做一個彙總和分析。 1.題目來源 Interleaving String 動態規劃二叉樹 Unique Binary Search Trees動態規劃二叉樹 Word Break動態規劃N/A Word Break II動態

7.21 暑假集訓——動態規劃

共17道題目,其中最後五題是拓展題,數位dp和插頭dp沒有寫出來 按照過題的順序記錄, 可以從下往上看~ E-Coins 題意: 告訴你 n 種錢幣的面值和數目,求【1,m】之間,有多少數目是用這些錢幣能恰好湊出的? 思路:經典裸題,參考《挑戰程式設計》

動態規劃例項:最小編輯距離

    問題:給定一個長度為m和n的兩個字串,設有以下幾種操作:替換(R),插入(I)和刪除(D)且都是相同的操作。尋找到轉換一個字串插入到另一個需要修改的最小(操作)數量。     關於編輯距離    編輯距離(Edit Distance),又稱Levenshtein距離