乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      白話算法之【動(dòng)態(tài)規(guī)劃入門】

       地質(zhì)博士 2018-01-30

      什么是動(dòng)態(tài)規(guī)劃?

              動(dòng)態(tài)規(guī)劃(Dynamic Programming,所以我們簡(jiǎn)稱動(dòng)態(tài)規(guī)劃為DP)運(yùn)籌學(xué)的一個(gè)分支,是求解決策過程(decision process)最優(yōu)化的數(shù)學(xué)方法。20世紀(jì)50年代初美國數(shù)學(xué)家R.E.Bellman等人在研究多階段決策過程(multistep decision process)的優(yōu)化問題時(shí),提出了著名的最優(yōu)化原理(principle of optimality),把多階段過程轉(zhuǎn)化為一系列單階段問題,利用各階段之間的關(guān)系,逐個(gè)求解,創(chuàng)立了解決這類過程優(yōu)化問題的新方法——動(dòng)態(tài)規(guī)劃。1957年出版了他的名著《Dynamic Programming》,這是該領(lǐng)域的第一本著作。

             動(dòng)態(tài)規(guī)劃算法通?;谝粋€(gè)遞推公式及一個(gè)或多個(gè)初始狀態(tài)。當(dāng)前子問題的解將由上一次子問題的解推出。使用動(dòng)態(tài)規(guī)劃來解題只需要多項(xiàng)式時(shí)間復(fù)雜度,因此它比回溯法、暴力法等要快許多。

             說了這么多術(shù)語,想必大家都很頭疼,現(xiàn)在讓我們通過一個(gè)例子來了解一下DP的基本原理。

      首先,我們要找到某個(gè)狀態(tài)的最優(yōu)解,然后在它的幫助下,找到下一個(gè)狀態(tài)的最優(yōu)解。這句話暫時(shí)理解不了沒關(guān)系,請(qǐng)看下面的例子:

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

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

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

      好了,讓我們從最小的i開始吧。當(dāng)i=0,即我們需要多少個(gè)硬幣來湊夠0元。由于1,35都大于0,即沒有比0小的幣值,因此湊夠0元我們最少需要0個(gè)硬幣。 (這個(gè)分析很傻是不是?別著急,這個(gè)思路有利于我們理清動(dòng)態(tài)規(guī)劃究竟在做些什么。這時(shí)候我們發(fā)現(xiàn)用一個(gè)標(biāo)記來表示這句湊夠0元我們最少需要0個(gè)硬幣。會(huì)比較方便,如果一直用純文字來表述,不出一會(huì)兒你就會(huì)覺得很繞了。那么,我們用d(i)=j來表示湊夠i元最少需要j個(gè)硬幣。于是我們已經(jīng)得到了d(0)=0,表示湊夠0元最小需要0個(gè)硬幣。當(dāng)i=1時(shí),只有面值為1元的硬幣可用,因此我們拿起一個(gè)面值為1的硬幣,接下來只需要湊夠0元即可,而這個(gè)是已經(jīng)知道答案的,即d(0)=0。所以,d(1)=d(1-1)+1=d(0)+1=0+1=1。當(dāng)i=2時(shí),仍然只有面值為1的硬幣可用,于是我拿起一個(gè)面值為1的硬幣,接下來我只需要再湊夠2-1=1元即可(記得要用最小的硬幣數(shù)量),而這個(gè)答案也已經(jīng)知道了。所以d(2)=d(2-1)+1=d(1)+1=1+1=2。一直到這里,你都可能會(huì)覺得,好無聊,感覺像做小學(xué)生的題目似的。因?yàn)槲覀円恢倍贾荒懿僮髅嬷禐?/span>1的硬幣!耐心點(diǎn),讓我們看看i=3時(shí)的情況。當(dāng)i=3時(shí),我們能用的硬幣就有兩種了:1元的和3元的( 5元的仍然沒用,因?yàn)槟阈枰獪惖臄?shù)目是3元!5元太多了親)。既然能用的硬幣有兩種,我就有兩種方案。如果我拿了一個(gè)1元的硬幣,我的目標(biāo)就變?yōu)榱耍簻悏?/span>3-1=2元需要的最少硬幣數(shù)量。即d(3)=d(3-1)+1=d(2)+1=2+1=3。這個(gè)方案說的是,我拿3個(gè)1元的硬幣;第二種方案是我拿起一個(gè)3元的硬幣,我的目標(biāo)就變成:湊夠3-3=0元需要的最少硬幣數(shù)量。即d(3)=d(3-3)+1=d(0)+1=0+1=1. 這個(gè)方案說的是,我拿1個(gè)3元的硬幣。好了,這兩種方案哪種更優(yōu)呢?記得我們可是要用最少的硬幣數(shù)量來湊夠3元的。所以,選擇d(3)=1,怎么來的呢?具體是這樣得到的:d(3)=min{d(3-1)+1, d(3-3)+1}。

      OK,碼了這么多字講具體的東西,讓我們來點(diǎn)抽象的。從以上的文字中,我們要抽出動(dòng)態(tài)規(guī)劃里非常重要的兩個(gè)概念:狀態(tài)和狀態(tài)轉(zhuǎn)移方程。

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

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

      有了狀態(tài)和狀態(tài)轉(zhuǎn)移方程,這個(gè)問題基本上也就解決了。當(dāng)然了,Talk is cheap,show me the code!

      1. int main()  
      2. {  
      3.     int a[3] = {1,3,5},sum = 11,cent = 0,dp[12];  
      4.     dp[0] = 0;  
      5.     for(int i = 1; i <= sum; i++) dp[i] = i;//我們假設(shè)存在1元的硬幣那么i元最多只需要i枚1元硬幣,當(dāng)然最好設(shè)置dp[i]等于無窮大  
      6.    
      7.     for(int i = 1; i <= sum; i++){  
      8.         for(int j = 0; j < 3; j++){  
      9.             if(i >= a[j] && dp[i - a[j]] + 1 < dp[i]){  
      10.                 dp[i] = dp[i- a[j] ] + 1;  
      11.             }  
      12.         }  
      13.     }  
      14.     cout<<dp[sum]<<endl;  
      15.     return 0;  
      16. }  


       

      下圖是當(dāng)i011時(shí)的解:


       

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

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

       

          通過硬幣問題我們初識(shí)DP的原理,其實(shí)可以說貪心問題是DP問題的特例,現(xiàn)在我們通過幾道題目加深對(duì)DP問題的理解

      數(shù)塔問題是動(dòng)態(tài)規(guī)劃經(jīng)典的題目,下面來初步講解下

      將一個(gè)由N行數(shù)字組成的三角形,如圖所以,設(shè)計(jì)一個(gè)算法,計(jì)算出三角形的由頂至底的一條路徑,使該路徑經(jīng)過的數(shù)字總和最大。

      學(xué)弟學(xué)妹們你們之前學(xué)過DFSBFS,第一眼看過去這題應(yīng)該用DFS解決,沒錯(cuò),DFS也可以,但是我們觀察下n行總共有(1 + 2 + 3 + 4+...+n) = 1+n*n/2個(gè)節(jié)點(diǎn),在遞歸求解的過程中很多節(jié)點(diǎn)被重復(fù)訪問了,這就導(dǎo)致時(shí)間大大增加,必然超時(shí)

      比如用遞歸的話,18這個(gè)節(jié)點(diǎn)被訪問了兩次

       

      但是如果用DP的話這個(gè)節(jié)點(diǎn)可以只訪問一次

       

      好了,現(xiàn)在我們用DP解決這道問題

       

      將上圖轉(zhuǎn)化一下:


      假設(shè)上圖用map[][]數(shù)組保存。

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

      則可以得到狀態(tài)轉(zhuǎn)移方程:

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

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

      當(dāng)用自頂而下的方法做時(shí),最后要在在最后一列數(shù)中找出最大值,

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

      所以我們將圖2根據(jù)狀態(tài)轉(zhuǎn)移方程可以得到圖3


      最大值是30.

      代碼如下:

      1. 1 #include <cstdio>    
      2. 2. #include <iostream>    
      3. 3. #include <algorithm>    
      4. 4. #include <cstring>    
      5. 5. using namespace std;    
      6. 6. int a[2000][2000];    
      7. 7. int main()    
      8. 8. {    
      9. 9.     int t,n,i,j;    
      10. 10.     while(~scanf("%d",&n))    
      11. 11.     {   
      12. 12.         for(i=0; i<n; i++)    
      13. 13.             for(j=0; j<=i; j++)    
      14. 14.                 scanf("%d",&a[i][j]);    
      15. 15.         for(i=n-1; i>0; i--)    
      16. 16.             for(j=0; j<i; j++)    
      17. 17.                 a[i-1][j]+=max(a[i][j],a[i][j+1]);    
      18. 18.         printf("%d\n",a[0][0]);    
      19. 19.     }    
      20. 20.     return 0;    
      21. 21. }    


       

      上面討論了兩個(gè)非常簡(jiǎn)單的例子?,F(xiàn)在讓我們來看看對(duì)于更復(fù)雜的問題,如何找到狀態(tài)之間的轉(zhuǎn)移方式(即找到狀態(tài)轉(zhuǎn)移方程)。為此我們要引入一個(gè)新詞叫遞推關(guān)系來將狀態(tài)聯(lián)系起來(說的還是狀態(tài)轉(zhuǎn)移方程)

      OK,上例子,看看它是如何工作的。

      一個(gè)序列有N個(gè)數(shù):A[1],A[2],…,A[N],求出最長非降子序列的長度。 (DP基本都會(huì)講到的一個(gè)問題LISlongest increasing subsequence)

      正如上面我們講的,面對(duì)這樣一個(gè)問題,我們首先要定義一個(gè)狀態(tài)來代表它的子問題,并且找到它的解。注意,大部分情況下,某個(gè)狀態(tài)只與它前面出現(xiàn)的狀態(tài)有關(guān),而獨(dú)立于后面的狀態(tài)。

      讓我們沿用入門一節(jié)里那道簡(jiǎn)單題的思路來一步步找到狀態(tài)狀態(tài)轉(zhuǎn)移方程。假如我們考慮求A[1],A[2],…,A[i]的最長非降子序列的長度,其中i<N,那么上面的問題變成了原問題的一個(gè)子問題(問題規(guī)模變小了,你可以讓i=1,2,3等來分析然后我們定義d(i),表示前i個(gè)數(shù)中以A[i]結(jié)尾的最長非降子序列的長度。OK,對(duì)照入門中的簡(jiǎn)單題,你應(yīng)該可以估計(jì)到這個(gè)d(i)就是我們要找的狀態(tài)。如果我們把d(1)d(N)都計(jì)算出來,那么最終我們要找的答案就是這里面最大的那個(gè)。狀態(tài)找到了,下一步找出狀態(tài)轉(zhuǎn)移方程。

      為了方便理解我們是如何找到狀態(tài)轉(zhuǎn)移方程的,我先把下面的例子提到前面來講。如果我們要求的這N個(gè)數(shù)的序列是:

      5,3,48,6,7

      根據(jù)上面找到的狀態(tài),我們可以得到:(下文的最長非降子序列都用LIS表示)

      · 1個(gè)數(shù)的LIS長度d(1)=1(序列:5)

      · 2個(gè)數(shù)的LIS長度d(2)=1(序列:3;3前面沒有比3小的)

      · 3個(gè)數(shù)的LIS長度d(3)=2(序列:34;4前面有個(gè)比它小的3,所以d(3)=d(2)+1)

      · 4個(gè)數(shù)的LIS長度d(4)=3(序列:3,48;8前面比它小的有3個(gè)數(shù),所以 d(4)=max{d(1),d(2),d(3)}+1=3)

      OK,分析到這,我覺得狀態(tài)轉(zhuǎn)移方程已經(jīng)很明顯了,如果我們已經(jīng)求出了d(1)d(i-1),那么d(i)可以用下面的狀態(tài)轉(zhuǎn)移方程得到:

      d(i) = max{1, d(j)+1},其中j<i,A[j]<=A[i]

      用大白話解釋就是,想要求d(i),就把i前面的各個(gè)子序列中,最后一個(gè)數(shù)不大于A[i]的序列長度加1,然后取出最大的長度即為d(i)。當(dāng)然了,有可能i前面的各個(gè)子序列中最后一個(gè)數(shù)都大于A[i],那么d(i)=1,即它自身成為一個(gè)長度為1的子序列。

      分析完了,上圖:(第二列表示前i個(gè)數(shù)中LIS的長度,第三列表示,LIS中到達(dá)當(dāng)前這個(gè)數(shù)的上一個(gè)數(shù)的下標(biāo),根據(jù)這個(gè)可以求出LIS序列)


       

      代碼:

      1. 1. #include <cstdio>    
      2. 2. #include <iostream>    
      3. 3. #include <algorithm>    
      4. 4. #include <cstring>    
      5. 5. usingnamespace std;    
      6. 6.      
      7. 7. int main()    
      8. 8. {    
      9. 9.     int dp[2000],a[2000],n;    
      10. 10.     while(cin>>n)    
      11. 11.     {    
      12. 12.         memset(dp,0,sizeof(dp));    
      13. 13.         intres = 0;    
      14. 14.         for(inti = 0; i < n; i++) cin>>a[i];    
      15. 15.      
      16. 16.         for(inti = 0; i < n; i++)    
      17. 17.         {    
      18. 18.             dp[i] = 1;    
      19. 19.             for(intj = 0; j < i; j++)    
      20. 20.             {    
      21. 21.                 if(a[j] < a[i])    
      22. 22.                 dp[i] = max(dp[i],dp[j] + 1);    
      23. 23.             }    
      24. 24.      
      25. 25.           res = max(res,dp[i]);    
      26. 26.         }    
      27. 27.      
      28. 28.         cout<<res<<endl;    
      29. 29.     }    
      30. 30.     return0;    
      31. 31. }  


      該算法的時(shí)間復(fù)雜度是O(n2 ),并不是最優(yōu)的解法。還有一種很巧妙的算法可以將時(shí)間復(fù)雜度降到O(nlogn),網(wǎng)上已經(jīng)有各種文章介紹它,這里就不再贅述。此題還可以用排序+LCS”來解,感興趣的話可自行Google,Baidu

       

      最后講一下最長上升公共子序列問題:

      問題描述

          什么是最長公共子序列呢?好比一個(gè)數(shù)列S,如果分別是兩個(gè)或多個(gè)已知數(shù)列的子序列,且是所有符合此條件序列中最長的,則S 稱為已知序列的最長公共子序列。

          舉個(gè)例子,如:有兩條隨機(jī)序列,如 1 3 4 5 5 and 2 4 5 5 7 6,則它們的最長公共子序列便是:4 5 5。

      LCS問題的解決思路

      · 

      窮舉法   

      · 

          解最長公共子序列問題時(shí)最容易想到的算法是窮舉搜索法,即對(duì)X的每一個(gè)子序列,檢查它是否也是Y的子序列,從而確定它是否為XY的公共子序列,并且在檢查過程中選出最長的公共子序列。XY的所有子序列都檢查過后即可求出XY的最長公共子序列。X的一個(gè)子序列相應(yīng)于下標(biāo)序列{1, 2, …, m}的一個(gè)子序列,因此,X共有2m個(gè)不同子序列(Y亦如此,如為2^n),從而窮舉搜索法需要指數(shù)時(shí)間(2^m * 2^n)。

      · 動(dòng)態(tài)規(guī)劃算法

          事實(shí)上,最長公共子序列問題也有最優(yōu)子結(jié)構(gòu)性質(zhì)。

      :

      Xi=x1?,xi﹥即X序列的前i個(gè)字符 (1≤i≤m)(前綴)

      Yj=y1?,yj﹥即Y序列的前j個(gè)字符 (1≤j≤n)(前綴)

      假定Z=z1?,zk∈LCS(X , Y)

      · 

      xm=yn(最后一個(gè)字符相同),則不難用反證法證明:該字符必是XY的任一最長公共子序列Z(設(shè)長度為k)的最后一個(gè)字符,即有zk = xm = yn 且顯然有Zk-1∈LCS(Xm-1 , Yn-1)Z的前綴Zk-1Xm-1Yn-1的最長公共子序列。此時(shí),問題化歸成求Xm-1Yn-1LCSLCS(X , Y)的長度等于LCS(Xm-1 , Yn-1)的長度加1)。

      · 

      · 

      xm≠yn,則亦不難用反證法證明:要么Z∈LCS(Xm-1, Y),要么Z∈LCS(X , Yn-1)。由于zk≠xmzk≠yn其中至少有一個(gè)必成立,若zk≠xm則有Z∈LCS(Xm-1 , Y),類似的,若zk≠yn 則有Z∈LCS(X , Yn-1)。此時(shí),問題化歸成求Xm-1YLCSXYn-1LCSLCS(X , Y)的長度為:max{LCS(Xm-1 , Y)的長度, LCS(X , Yn-1)的長度}。

      · 

          由于上述當(dāng)xm≠yn的情況中,求LCS(Xm-1 , Y)的長度與LCS(X , Yn-1)的長度,這兩個(gè)問題不是相互獨(dú)立的:兩者都需要求LCS(Xm-1,Yn-1)的長度。另外兩個(gè)序列的LCS中包含了兩個(gè)序列的前綴的LCS,故問題具有最優(yōu)子結(jié)構(gòu)性質(zhì)考慮用動(dòng)態(tài)規(guī)劃法。

          也就是說,解決這個(gè)LCS問題,你要求三個(gè)方面的東西:1、LCSXm-1,Yn-1+1;2、LCSXm-1,Y),LCSX,Yn-1);3、max{LCSXm-1,Y),LCSXYn-1}。

          行文至此,其實(shí)對(duì)這個(gè)LCS的動(dòng)態(tài)規(guī)劃解法已敘述殆盡,不過,為了成書的某種必要性,下面,我試著再多加詳細(xì)闡述這個(gè)問題。

      第三節(jié)、動(dòng)態(tài)規(guī)劃算法解LCS問題

      3.1、最長公共子序列的結(jié)構(gòu)

          最長公共子序列的結(jié)構(gòu)有如下表示:

          設(shè)序列X=<x1, x2, …, xm>Y=<y1, y2, …, yn>的一個(gè)最長公共子序列Z=<z1, z2, …, zk>,則:

      1. xm=yn,則zk=xm=ynZk-1Xm-1Yn-1的最長公共子序列;

      2. xm≠ynzk≠x,ZXm-1Y的最長公共子序列;

      3. xm≠ynzk≠yn ,則ZXYn-1的最長公共子序列。

          其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>

      3、2.子問題的遞歸結(jié)構(gòu)

          由最長公共子序列問題的最優(yōu)子結(jié)構(gòu)性質(zhì)可知,要找出X=<x1, x2, …, xm>Y=<y1, y2, …, yn>的最長公共子序列,可按以下方式遞歸地進(jìn)行:當(dāng)xm=yn時(shí),找出Xm-1和Yn-1的最長公共子序列,然后在其尾部加上xm(=yn)即可得XY的一個(gè)最長公共子序列。當(dāng)xm≠yn時(shí),必須解兩個(gè)子問題,即找出Xm-1和Y的一個(gè)最長公共子序列及XYn-1的一個(gè)最長公共子序列。這兩個(gè)公共子序列中較長者即為XY的一個(gè)最長公共子序列。

          由此遞歸結(jié)構(gòu)容易看到最長公共子序列問題具有子問題重疊性質(zhì)。例如,在計(jì)算XY的最長公共子序列時(shí),可能要計(jì)算出XYn-1及Xm-1和Y的最長公共子序列。而這兩個(gè)子問題都包含一個(gè)公共子問題,即計(jì)算Xm-1和Yn-1的最長公共子序列。

          與矩陣連乘積最優(yōu)計(jì)算次序問題類似,我們來建立子問題的最優(yōu)值的遞歸關(guān)系。用c[i,j]記錄序列Xi和Yj的最長公共子序列的長度。其中Xi=<x1, x2, …, xi>,Yj=<y1, y2, …, yj>。當(dāng)i=0j=0時(shí),空序列是Xi和Yj的最長公共子序列,故c[i,j]=0。其他情況下,由定理可建立遞歸關(guān)系如下:

       

      代碼如下:

      1. 1. #include <cstdio>    
      2. 2. #include <iostream>    
      3. 3. #include <algorithm>    
      4. 4. #include <cstring>    
      5. 5. using namespace std;    
      6. 6.      
      7. 7. int main()    
      8. 8. {    
      9. 9.     string str1,str2;    
      10. 10.     int dp[200][200];    
      11. 11.     while(cin>>str1>>str2)    
      12. 12.     {    
      13. 13.         memset(dp,0,sizeof(dp));    
      14. 14.      
      15. 15.         int la = str1.length();    
      16. 16.         int lb = str2.length();    
      17. 17.      
      18. 18.         for(int i = 1; i <= la; i++)    
      19. 19.             for(int j = 1; j <= lb; j++)    
      20. 20.         {    
      21. 21.             if(str1[i - 1] == str2[j - 1])    
      22. 22.             {    
      23. 23.                 dp[i][j] = dp[i-1][j-1]+1;    
      24. 24.             }    
      25. 25.             else dp[i][j] = max(dp[i-1][j],dp[i][j-1]);    
      26. 26.         }    
      27. 27.         cout<<dp[la][lb]<<endl;    
      28. 28.     }    
      29. 29.     return 0;  


       

      講到這想必對(duì)DP問題有一個(gè)大概的認(rèn)識(shí)了吧?乘熱打鐵,我們?nèi)?/span>HDU刷幾道簡(jiǎn)單題練練手感!

       

      HDU2191

      HDU1159

      HDU1432

      HDU2084

      DP問題是ACM里面最難的,因?yàn)樘妓季S能力了,只有將狀態(tài)轉(zhuǎn)移方程推出來才能解決問題,DP問題也是面試的時(shí)候最容易考到的,希望大家好好學(xué)DP,至少在面試的時(shí)候不吃虧。

      DP問題還有比較難的,分為數(shù)字DP,插頭DP,狀態(tài)壓縮DP,概率DP,組合DP,樹狀DP等等都是非常難理解的,但是也很有趣,有興趣的可以找資料學(xué)習(xí)


      最近李建中老師的算法課上完了,他的課大部分都是在講算法的數(shù)學(xué)證明,這對(duì)算法本身的理解并沒有花大手筆,于是我結(jié)合自己ACM一年多的算法經(jīng)驗(yàn)和一堆收集的資料,準(zhǔn)備寫專題【白話數(shù)據(jù)結(jié)構(gòu)和算法】,大家多多關(guān)注,一起加油~~~~

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多