1. 程式人生 > >幾個小問題理解動態規劃

幾個小問題理解動態規劃

求職期間,做很多公司的筆試題,最後的程式設計題都是往往都能用動態規劃的思路解決,接下來,說一說動態規劃問題的個人理解:

首先,解決動態規劃問題掌握兩點:

1. 動態規劃中有三個重要的概念:最優子結構、邊界、狀態轉移公式

2. 動態規劃問題的解決思路:從上往底分析,自底向上求解

以例題說明:

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

題目一:有一座高度是10級臺階的樓梯,從下往上走,每跨一步只能向上

1級或者2級臺階。要求用程式來求出一共有多少種走法。

    解:假設只差一步就走到10級臺階,這時會出現兩種情況,一是走到第九級,接下來只需一步跨1級;二是走到第八級,接下來一步只需跨2級。如果0到9級臺階有F(9)種走法,0到8級臺階有F(8)種,則0到10級臺階有F(8)+F(9)種走法。以此歸納:

F(1)=1

F(2)=2

F(n)=F(n-1)+F(n-2)  (n>=3)

這裡F(8)和F(9)是F(10)的最優子結構;F(1)=1和F(2)=2是邊界;F(n)=F(n-1)+F(n-2)是階段和階段之間的狀態轉移公式。

我們用到的分析方法是從最頂端開始,解決問題確實從底部開始。這裡的原因在於,如果採用從頂部開始計算,其過程類似於一個二叉樹,中間有很多重複的計算,複雜度很高。而從底部開始計算,直截了當。

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

接下來,考慮一個更復雜些的問題:

題目二:我們有面值為1元3元5元的硬幣若干枚,如何用最少的硬幣湊夠11元?

    解:類似題目一的解決思路,假設只差一枚硬幣就湊夠11元,則有三種情況,一是已有10元,差一枚1元的;二是已有8元,差一枚3元的;三是已有6元,差一枚5元的;如果湊夠10元最少的硬幣數是F(10),湊夠8元最少的硬幣數是F(8),湊夠6元最少的硬幣數是F(6),則湊夠11元的最少硬幣數是min{F(10)+1,F(8)+1,F(6)+1}。以此歸納:

F(1)=1

F(2)=2

F(3)=1

F(4)=2

F(5)=1

F(n)=min{F(n-1)+1,F(n-3)+1,F(n-5)+1}   (n>=6)

到此,最優子結構、邊界、態轉移公式顯而易見,問題可解。

\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

接下來,考慮一個更更復雜的問題:

題目三:

問題:有一個國家發現了5座金礦,每座金礦的黃金儲量不同,需要參與挖掘的工人數也不同(情況如下圖)。

金礦編號黃金儲量需要人數
15005
22003
33004
43503
54005

參與挖礦工人的總數是10人。每座金礦要麼全挖,要麼不挖,不能派出一半人挖取一半金礦。要求用程式求解出,要想得到儘可能多的黃金,應該選擇挖取哪幾座金礦?

    解:依然類似之前提到的分析方法。自頂向下分析,假設10人4個金礦的最優選擇收益為F[10;4],則10人五個金礦的最優選擇收益有兩種情況,一是仍為10人4個金礦的最優選擇收益,二是,(10-5)人4個金礦的最優選擇收益再加上第5個金礦收益。其區別實際上就是是否選擇第5個金礦,。以此歸納:

F[10;1]=w1  (p1<=10)

F[10,1]=0  (p1>10)

F[10,n]=max{F[10,n-1],F[10-pn,n-1]+wn}   (pn<=10)

F[10,n]=F[n-1]  (pn>10)

這裡的最優子結構為,F[10,5]=max{F[10,4],F[10-5,4]+400}   (5<=10),;邊界為F[10;1]=w1  (p1<=10)和F[10,1]=0  (p1>10);狀態轉移公式為F[10,n]=max{F[10,n-1],F[10-pn,n-1]+wn}   (pn<=10)  和  F[10,n]=F[n-1]  (pn>10)

其C++程式碼如下:

  1. #include<iostream>
  2. usingnamespace std;  
  3. int main()  
  4. {  
  5.     int n=5,w=10;                            //金礦數,挖礦工人總數
  6.     int p[]={0,5,3,4,3,5};                    //每個礦需要的工人數
  7.     int v[]={0,500,200,300,350,400};  //每個礦的價值
  8.     int Preresult[19];  
  9.     int t;  
  10.     for(int i=1;i<=10;i++)  
  11.     {  
  12.         if(i<p[1])  
  13.         {  
  14.             Preresult[i]=0;  
  15.         }  
  16.         else
  17.         {  
  18.             Preresult[i]=v[1];  
  19.         }  
  20.     }  
  21.     int result[19]={0};  
  22.     Preresult[0]=0;  
  23.     for(int i=2;i<=n;i++)  
  24.     {  
  25.         for(int j=1;j<=w;j++)  
  26.         {  
  27.             //這一處理是避免因訪問下標為負的元素而產生異常或者指定的儲存單元意外存在資料影響最終結果
  28.             if(j-p[i]<0)  
  29.             {  
  30.                 t=-102876;  
  31.             }  
  32.             else
  33.             {  
  34.                 t=Preresult[j-p[i]];  
  35.             }  
  36.             result[j]=max(Preresult[j],t+v[i]);  
  37.         }  
  38.         for(int k=1;k<=10;k++)  
  39.         {  
  40.             Preresult[k]=result[k];  
  41.         }  
  42.     }  
  43.     cout<<result[10]<<endl;  
  44. system("pause");  
  45. return 0;  
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

接下來,考慮一個更更更復雜些的問題:

題目四:給定一個矩陣m,從左上角開始每次只能向右走或者向下走,最後達到右下角的位置,路徑中所有數字累加起來就是路徑和,返回所有路徑的最小路徑和,如果給定的m如下,那麼路徑1,3,1,0,6,1,0就是最小路徑和,返回12。


1 3 5 9
8 1 3 4
5 0 6 1

8 8 4 0

  解:做類似的分析,走到第(i ,j)個數時,只可能是從(i-1 ,j)或是(i ,j-1)走來的,路徑(i ,j)的階段依賴的是(i-1 ,j)和(i ,j-1)的子階段,所以狀態轉移公式為dp[i][j] =a[i][j] + min(dp[i-1][j]+ dp[i][j-1]),其C++程式碼如下:

  1. #include <iostream>
  2. #include <algorithm>
  3. usingnamespace std;  
  4. int dp[4][4] = {};     //全域性陣列,存放決策表
  5. int main(int argc,char** argv)  
  6. {  
  7.     int a[4][4] = {1,3,5,9,8,1,3,4,5,0,6,1,8,8,4,0};  //矩陣儲存a[i][j]
  8.     for (int i = 0;i < 4;++i)  
  9.     {  
  10.         for (int j = 0;j < 4;++j)  
  11.         {  
  12.             if (i==0 && j==0)                         //邊界條件問題需要考慮到
  13.             {  
  14.                 dp[i][j] = a[i][j];  
  15.             }  
  16.             elseif (i==0 && j!=0)  
  17.             {  
  18.                 dp[i][j] = a[i][j] + dp[i][j-1];  
  19.             }  
  20.             elseif (i!=0 && j==0)  
  21.             {  
  22.                 dp[i][j] = a[i][j] + dp[i-1][j];  
  23.             }  
  24.             else
  25.             {  
  26.                 dp[i][j] = a[i][j] + min(dp[i-1][j],dp[i][j-1]);  
  27.             }  
  28.         }  
  29.     }  
  30.     cout<<"走到位置"<<"(4,4)"<<"最短路徑為:";  
  31.     cout<<dp[3][3]<<endl;           //好像到這裡又腦殘了一次,真輸出dp[4][4]了~
  32.     system("pause");  
  33.     return 0;  
  34. }

相關推薦

經典的動態規劃演算法

一、動態規劃基本思想     一般來說,只要問題可以劃分成規模更小的子問題,並且原問題的最優解中包含了子問題的最優解,則可以考慮用動態規劃解決。動態規劃的實質是分治思想和解決冗餘,因此,動態規劃是一種將問題例項分解為更小的、相似的子問題,並存儲子問題的解而避免計算重複的子問題,以解決最優化問題的演算法策略

問題理解動態規劃

求職期間,做很多公司的筆試題,最後的程式設計題都是往往都能用動態規劃的思路解決,接下來,說一說動態規劃問題的個人理解:首先,解決動態規劃問題掌握兩點:1. 動態規劃中有三個重要的概念:最優子結構、邊界、狀態轉移公式。2. 動態規劃問題的解決思路:從上往底分析,自底向上求解。以

步驟教你線上使用浪潮webblos做raid---簡單明了!

幾個小步驟教你線上使用浪潮webblos做raid 幾個小步驟教你線上使用浪潮webblos做raid 簡單明了教你線上使用浪潮webblos做raid,在這裏就不啰嗦了!直接進入正題---圖片表達!選擇configureation v….選擇新建 (new)選擇手動 (M

C++ string中的陷阱,你掉進過嗎?

stl 試題 賦值 clu ror ati world mod iostream C++開發的項目難免會用到STL的string。使用管理都比char數組(指針)方便的多。但在得心應手的使用過程中也要警惕幾個小陷阱。避免我們項目出bug卻遲遲找不到原因。1. 結構體中的

Ch1的問題

最大值 需要 是什麽 題目 優先級 思考 問題 優先 網上 接下來的題目需要更多的思考:如何用實驗方法確定以下問題的答案?註意,不要查書,也不要在網上搜索答案,必須親手嘗試——實踐精神是極其重要的。 問題1:int型整數的最小值和最大值是多少(需要精確值)? 問題2:d

NuGet的技巧

com packages 影響 頁面 兼容 images eight 記錄 cef 因為可視化庫程序包管理器的局限性,有很多需要的功能在界面中無法完成。 以下技巧均需要在“程序包管理器控制臺”中使用命令來完成。 一、改變項目目標框架後,更新程序包 當改變項目的目標框架後,無

高效的技巧

編碼格式 輸出 indent 默認 asc encode mps family 寫入 json json 序列化dumps之後,數據會變成很長的一行,如果,數據量非常大就會相當不易查看,使用indent參數來輸出便於查看的JSON。 如: { "終點站": "貴陽站", "

關於信息化的故事,摘自麥楓網

了解 信心 放大 凝聚力 是什麽 小故事 工作 組織 外部 企業的信息化的實行是增強企業反響才幹、進步企業效率、改進企業管理方式的一項工作,選擇實施一項性能良好的信息化軟件是作為信息化的主管的一項重要工作,下面我們就幾個小故事來看一看:  一、指導看電腦  這是發作在幾年前

關於docker使用的問題

atm who edi tbb dram ++z bug dockerd 生成 由於剛接觸docker踩了幾個坑,希望本文對網癮少年有所幫助。 Docker分CE版(社區版)和EE版(商用版),具體安裝流程參考文檔介紹,在此不再贅述。下面分Windows和Linux分別踩

OSPF中概念

虛鏈路 net ospf -1 路由器 rtu 網絡 概念 link OSPF的有以下幾種LSA: Type-1 lsa (router isa) Type-2 lsa (network lsa) Type-3 lsa (network summary lsa) Type

PHP時間戳的問題示例

北京時間 content date def 當前 時間戳 day 問題 獲得 <?php header("Content-type:text/html;charset=utf-8"); //設置北京時間為默認時區 date_default

基於《構建之法》的見解

關系 希望 階段 周期 這一 都在 urn blog foo 第一章 計算機科學和軟件工程的關系 中國大陸的高校中大致有下面三種將計算機軟件的機構: 計算機科學與技術系或學院 軟件學院 軟件工程系、軟件工程學院 問題1: 這一章有講到

Python的程序,其實我覺得可以稱作初學時的基礎算法

基本 什麽 否則 col 重新 保留 put span pri 昨天學習的,今天做一下整理,以前學過幾天c,感覺什麽都沒有搞出來,有點泄氣,看到Python後試試,從最基本的東西學起,希望不要辜負我的這一點熱情。 if語句的應用 1 n=1 2 while

技術好卻進不了大公司?iOS程序員面試的技巧你可要收好了

朋友 知識 了解 一點 今天 刪除 就會 為什麽 年輕 前言: 有很多程序員,專業技術挺好,項目經驗充足,簡歷上金碧輝煌,也面試了很多國內大廠,但就是沒有一家能成功的。處境可以說是相當尷尬。 大家都知道程序員本身就是要吃年輕飯,不僅是技術活,也是體力活。早點跳槽,早點漲薪,

CCS下載MSP430編譯遇到的問題

例程 usb res 斷點 uil 遇到 問題 定義 嘗試 1.連接顯示屏後要把旋鈕扭在最下;不然下載會報錯不進去,自己嘗試一下2.例程存放路徑不要出現中文,或者空格,不然Debug會報錯;3.器件選擇MSP430;Connection選擇TI MSP430 USB14.下

nyoj 49-開心的明(動態規劃, 0-1背包問題)

限定 std btn inpu 描述 背包 代碼 OS 出了 49-開心的小明 內存限制:64MB 時間限制:1000ms Special Judge: No

JS的測試錯題改錯

JS小測試var a=3;var b=2;var c=a+++b;c的值為(5),a的值為(4)算法過程:a=3 b=2 c=a+++b;a++後,a=4,但a不參與預算,所以c=a+b=3+2=5;其實將計算式改成:c=a+b,a++之後更能理解。2.var a=2,b=1,c=3;if(a<b)if

maven docker 插件集成的

telnet service skip could 服務 request execution 系統 怎麽 昨晚看springboot視頻的時候,發現可以使用docker-maven-plugin這個插件直接build出 docker 鏡像到遠程服務器上,感覺很方便,於是自己

ETL工具kettle的插件(字符串替換,字段選擇,將字段值設置為常量)

sha oracle rac 正則 com 修改字符集 繼續 kettle 輸出 繼續給大家介紹幾個小組件:一、字符串替換這個功能類似於oracle的replace函數,就是將某個字段的某些字符替換成我們給定的字符首先,選擇【輸入流字段】,【輸出流字段】自己命名(就是用來保

CSS3實現的loading效果

css linear 1.2 普通 dong 500px 交叉 yellow index     昨晚上閑的沒事突然想做幾個小loading效果,下面是昨晚上做的幾個小案例,分享給大家     1.水波loading:這個loading是我覺得非常簡單,但是看上去的效果卻非