日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法-动态规划(1)

發布時間:2025/3/20 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法-动态规划(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是動態規劃?

動態規劃(Dynamic Programming,所以我們簡稱動態規劃為DP)是運籌學的一個分支,是求解決策過程(decision process)最優化的數學方法。20世紀50年代初美國數學家R.E.Bellman等人在研究多階段決策過程(multistep decision process)的優化問題時,提出了著名的最優化原理(principle of optimality),把多階段過程轉化為一系列單階段問題,利用各階段之間的關系,逐個求解,創立了解決這類過程優化問題的新方法——動態規劃。1957年出版了他的名著《Dynamic Programming》,這是該領域的第一本著作。動態規劃算法通常基于一個遞推公式及一個或多個初始狀態。當前子問題的解將由上一次子問題的解推出。使用動態規劃來解題只需要多項式時間復雜度,因此它比回溯法、暴力法等要快許多。說了這么多術語,想必大家都很頭疼,現在讓我們通過一個例子來了解一下DP的基本原理。

首先,我們要找到某個狀態的最優解,然后在它的幫助下,找到下一個狀態的最優解。這句話暫時理解不了沒關系,請看下面的例子:

如果我們有面值為1元、3元和5元的硬幣若干枚,如何用最少的硬幣湊夠11元?

我們憑直觀感覺告訴自己,先選面值最大,因此最多選2枚5元的硬幣,現在是10元了,還差一元,接下來我們挑選第二大的3元硬幣,發現不行(10+3=13超了),因此我們繼續選第三大的硬幣也就是1元硬幣,選一個就可以(10+1=11),所以總共用了3枚硬幣湊夠了11元。這就是貪心法,每次選最大的。但是我們將面值改為2元,3元和5元的硬幣,再用貪心法就不行了。為什么呢?按照貪心思路,我們同樣先取2枚最大5元硬幣,現在10元了,還差一元,接下來選第二大的,發現不行,再選第三大的,還是不行,這時用貪心方法永遠湊不出11元,但是你仔細看看,其實我們可以湊出11元的,2枚3元硬幣和1枚五元硬幣就行了,這是人經過思考判斷出來了的,但是怎么讓計算機算出來呢?這就要用動態規劃的思想:

首先我們思考一個問題,如何用最少的硬幣湊夠i元(i<11)?為什么要這么問呢?兩個原因:1.當我們遇到一個大問題時,總是習慣把問題的規模變小,這樣便于分析討論。 2.這個規模變小后的問題和原來的問題是同質的,除了規模變小,其它的都是一樣的,本質上它還是同一個問題(規模變小后的問題其實是原問題的子問題)。

好了,讓我們從最小的i開始吧。當i=0,即我們需要多少個硬幣來湊夠0元。由于1,3,5都大于0,即沒有比0小的幣值,因此湊夠0元我們最少需要0個硬幣。 (這個分析很傻是不是?別著急,這個思路有利于我們理清動態規劃究竟在做些什么。) 這時候我們發現用一個標記來表示這句“湊夠0元我們最少需要0個硬幣。”會比較方便,如果一直用純文字來表述,不出一會兒你就會覺得很繞了。那么,我們用d(i)=j來表示湊夠i元最少需要j個硬幣。于是我們已經得到了d(0)=0,表示湊夠0元最小需要0個硬幣。當i=1時,只有面值為1元的硬幣可用,因此我們拿起一個面值為1的硬幣,接下來只需要湊夠0元即可,而這個是已經知道答案的,即d(0)=0。所以,d(1)=d(1-1)+1=d(0)+1=0+1=1。當i=2時,仍然只有面值為1的硬幣可用,于是我拿起一個面值為1的硬幣,接下來我只需要再湊夠2-1=1元即可(記得要用最小的硬幣數量),而這個答案也已經知道了。所以d(2)=d(2-1)+1=d(1)+1=1+1=2。一直到這里,你都可能會覺得,好無聊,感覺像做小學生的題目似的。因為我們一直都只能操作面值為1的硬幣!耐心點,讓我們看看i=3時的情況。當i=3時,我們能用的硬幣就有兩種了:1元的和3元的( 5元的仍然沒用,因為你需要湊的數目是3元!5元太多了親)。既然能用的硬幣有兩種,我就有兩種方案。如果我拿了一個1元的硬幣,我的目標就變為了:湊夠3-1=2元需要的最少硬幣數量。即d(3)=d(3-1)+1=d(2)+1=2+1=3。這個方案說的是,我拿3個1元的硬幣;第二種方案是我拿起一個3元的硬幣,我的目標就變成:湊夠3-3=0元需要的最少硬幣數量。即d(3)=d(3-3)+1=d(0)+1=0+1=1. 這個方案說的是,我拿1個3元的硬幣。好了,這兩種方案哪種更優呢?記得我們可是要用最少的硬幣數量來湊夠3元的。所以,選擇d(3)=1,怎么來的呢?具體是這樣得到的:d(3)=min{d(3-1)+1, d(3-3)+1}。

OK,碼了這么多字講具體的東西,讓我們來點抽象的。從以上的文字中,我們要抽出動態規劃里非常重要的兩個概念:狀態和狀態轉移方程。

上文中d(i)表示湊夠i元需要的最少硬幣數量,我們將它定義為該問題的"狀態",這個狀態是怎么找出來的呢?根據子問題定義狀態。你找到子問題,狀態也就浮出水面了。最終我們要求解的問題,可以用這個狀態來表示:d(11),即湊夠11元最少需要多少個硬幣。那狀態轉移方程是什么呢?既然我們用d(i)表示狀態,那么狀態轉移方程自然包含d(i),上文中包含狀態d(i)的方程是:d(3)=min{d(3-1)+1, d(3-3)+1}。沒錯,它就是狀態轉移方程,描述狀態之間是如何轉移的。當然,我們要對它抽象一下,

d(i)=min{ d(i-vj)+1 },其中i-vj >=0,vj表示第j個硬幣的面值;

有了狀態和狀態轉移方程,這個問題基本上也就解決了。當然了,Talk is cheap,show me the code!

int main() { int a[3] = {1,3,5},sum = 11,cent = 0,dp[12]; dp[0] = 0; for(int i = 1; i <= sum; i++) dp[i] = i;//我們假設存在1元的硬幣那么i元最多只需要i枚1元硬幣,當然最好設置dp[i]等于無窮大 for(int i = 1; i <= sum; i++){ for(int j = 0; j < 3; j++){ if(i >= a[j] && dp[i - a[j]] + 1 < dp[i]){ dp[i] = dp[i- a[j] ] + 1; } } } cout<<dp[sum]<<endl; return 0; }

下圖是當i從0到11時的解:

從上圖可以得出,要湊夠11元至少需要3枚硬幣。

此外,通過追蹤我們是如何從前一個狀態值得到當前狀態值的,可以找到每一次我們用的是什么面值的硬幣。比如,從上面的圖我們可以看出,最終結果d(11)=d(10)+1(面值為1),而d(10)=d(5)+1(面值為5),最后d(5)=d(0)+1 (面值為5)。所以我們湊夠11元最少需要的3枚硬幣是:1元、5元、5元。

通過硬幣問題我們初識DP的原理,其實可以說貪心問題是DP問題的特例,現在我們通過幾道題目加深對DP問題的理解

數塔問題是動態規劃經典的題目,下面來初步講解下

將一個由N行數字組成的三角形,如圖所以,設計一個算法,計算出三角形的由頂至底的一條路徑,使該路徑經過的數字總和最大。

學弟學妹們你們之前學過DFS和BFS,第一眼看過去這題應該用DFS解決,沒錯,DFS也可以,但是我們觀察下n行總共有(1 + 2 + 3 + 4+…+n) = (1+n)*n/2個節點,在遞歸求解的過程中很多節點被重復訪問了,這就導致時間大大增加,必然超時

比如用遞歸的話,18這個節點被訪問了兩次

但是如果用DP的話這個節點可以只訪問一次

好了,現在我們用DP解決這道問題

將上圖轉化一下:

假設上圖用map[][]數組保存。

令f[i][j]表示從頂點(1, 1)到頂點(i, j)的最大值。

則可以得到狀態轉移方程:

f[i][j] = max(f[i+1][j], f[i+1][j+1]) + map[i][j]

此題既適合自頂而下的方法做,也適合自底而上的方法,

當用自頂而下的方法做時,最后要在在最后一列數中找出最大值,

而用自底而上的方法做時,f[1][1]即為最大值。

所以我們將圖2根據狀態轉移方程可以得到圖3:

最大值是30.

代碼如下:

#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; int a[2000][2000]; int main() { int t,n,i,j; while(~scanf("%d",&n)) { for(i=0; i<n; i++) for(j=0; j<=i; j++) scanf("%d",&a[i][j]); for(i=n-1; i>0; i--) for(j=0; j<i; j++) a[i-1][j]+=max(a[i][j],a[i][j+1]); printf("%d\n",a[0][0]); } return 0; }

出自:http://blog.csdn.net/u013445530/article/details/45645307

總結

以上是生活随笔為你收集整理的算法-动态规划(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。