1. 程式人生 > >重複口胡的動態規劃

重複口胡的動態規劃

   今天老師口胡了一波動歸,如果有其他人發了一篇差不多的,一定是我同學!

動態規劃:

範圍:適於解決多階段、多決策、最優解(求方法數)問題

與貪心、分治的對比:

 貪心 :

   當前階段 ,選最優(每次選取能取到的最優值,從而得到一個區域性最優值) 。例題:潛水

 分治:   

      分而治之  ,也就是分->治
      例題(或用法):快排 ,歸併排序

 動態規劃:  

     當前階段, 記錄 所有的最優  (也就是常說的空間換時間)

     由於分部分的時候,重合部分經常出現,就會出現大量重複的遞迴呼叫,然而用了記憶化搜尋來解決,可使動歸 進一步 轉換為遞推。

   動態規劃的兩個必要條件:

  1)無後效性:當前的最優解與後面無關;
  2)最優子結構:每次都要保證最有值;

  看到這兩個條件滿足就基本確定是動態規劃了;

  動歸解題步驟:

  1)確定能用動態規劃解決;
  2)劃分階段:時間,空間,順序;(不同階段效率不同,具體題目具體分析)
     拓撲排序*也是階段劃分
     floyd 的k迴圈
  3)設定狀態:前i階段的xxxxxx的最優值是什麼
     設定f[i]([j]),表示某個狀態的最優值
     洛谷 2519,為海亮題庫(HLOJ)407加強版;
     狀態是幾維,迴圈也就是幾重迴圈
   
     區間類:從第i個到第j個的最優值;
   
4)建立狀態轉移方程
   當前的狀態(最優值、方案數)有前面那些狀態推匯出;
   繼續加迴圈;
   
  例:零一揹包:

    f[i][j]狀態表示 前i個物品佔據容量為j的揹包的最優值
    故轉移方程為
     f[i][j]=max(f[i-1][j](0,即不取),f[i-1][j-w[i]]+v[i](1,表示取));

*拓撲排序定義:拓撲排序順序就是在圖上做動態規劃的階段劃分;(滿足條件時)

動態規劃的分類:

   動態規劃分類的最終目的,是不分類。
 
1)  資源分配
   HLOJ411機械分配: f[i][j]   狀態表示前i個公司 分配 j 臺機器
           412馬棚:狀態:前i匹馬分j個馬棚
   使用三重迴圈實現;
   延伸:輸出方案,是noip裡也會考察的
2)  揹包


   a ) 0/1  揹包:
   f[i][j]=  max(f[i-1][j],f[i-1][j-c[i]]+w[i])
                     不要         要第i個物品
    用一維實現狀態 :  f[j]   i迴圈(v...c[i]) 倒著迴圈;

PS:零一揹包是其他所有揹包類問題及變形的基礎,所以一定要掌握,詳見揹包九講(https://wenku.baidu.com/view/5e9062717fd5360cba1adb37.html)
  b)完全揹包
   f[i][j]=  max(f[i-1][j],f[i][j-c[i]]+w[i])
                     不要         要第i個物品  
                     
        一維狀態 :  f[j]   i迴圈(c[i]...v) 正著迴圈;    
    

PS:觀察零一揹包與完全揹包二維狀態、一維狀態的分別不同之處並思考原因。
  c)多重揹包
    每個物品有多個,第i個物品有k個,  1倍,2倍,3倍……k倍
      二進位制優化  Log2(k)
    13= 1   12
        2   10
        4   6
        6
  d)二維體積揹包
       f[i][j][k]設定三維的狀態,其實與零一沒什麼區別,只要再加上一層迴圈而已,轉移方程也類似

       同時也可以壓縮為二維的:

       f[j][k]=max(f[j][k],f[j-w1[i]][k-w2[i]]+v[i]);

  e)分組:

可以將每組都合併成一個物品,再按照零一來做;
      
  f)有依賴 (樹形動態規劃):

這個。。。已經不在今天的範圍之內了。。。

      若是想學習還是另請高明吧。

PS:揹包類問題是動態規劃的重點考點,熟悉掌握才能應對考場上的各種變形、結合的揹包問題。
 

3)  雙程序:

 兩個程序,用i、j分別指示;通過兩個程序之間的關係來求解;

     具體的可以自行百度;

     例題:最長公共子序列、構建雙塔等;
       
4)  區間類  
    區間問題的狀態設定、轉移方程都不同於其他的dp,

    f[i][j]表示從第i個 到 第 j個 的最優值 

    f[i][j];
    階段 : 區間長度
    for (int p=0;p<=n;p++) //區間長度
      for (int i=1;i<=n;i++)//起點位置
      {
         int j=i+p;//終點
         if (j>n)  break;//還可以這樣。。。。
         求 f[i][j]
         
      }
    環狀的區間類: 長度變兩倍,依次去做
    
5) 二維  由線性變成了平面
    呵呵,我還沒學呢;

    例題:農田個數、創意吃魚;

    聽說都是有意思的題;

----------------------------------------------------------------------------------------------------------------------------

   呼,就是這樣,劉老師口胡一波的東西我加了一些改動就放上來了。。。。