動態規劃筆記

動態規劃筆記

由於自己是非計算機專業,而對編程學習比較感興趣,特學習算法導論一書,根據書上僞代碼來練習,一來提高自己算法思維,二來督促自己好好學習,不能虛度光陰。

一:思想

  動態規劃,通常用來求解最優化問題,這類問題有很多可行解,我們希望尋找其最優解,通常是最大值最小值。
  具體步驟就是一個大問題可以分爲很多子問題,通過求解小規模的子問題,進而組合子問題得到原問題的解。使用動態規劃解決問題,需要具備以下兩個因素。

  • 最優子結構:一個問題的最優解包含子問題的最優解。也就是一個最優解,它也必須是字問題的最優解。
  • 重疊子問題:問題的遞歸算法要重複求解相同的子問題,而不是一直生成新問題。

二:例題

1 鋼條切割問題

對於長度爲 i 的鋼條的價格pi 如下。如何切割達到價值最大。

這裏寫圖片描述

  • 最優子結構:當鋼條完成首次切割後,變成兩段獨立的鋼條。進而求解兩段獨立的鋼條最優解,然後相加即可。
  • 重疊子問題:鋼條越切越少,則子問題重疊的越多。
    我們將鋼條從左邊切下的長度記爲i的那一段,只對右邊長度n-i的一段繼續進行切割(遞歸求解),對左邊的不再進行切割。即問題轉化爲:第一段長度求解如下最大值:
    rn=max(pi+pni),i=1...n
    .

自頂向下法自然求解
所謂自頂向下法,是直接利用遞歸的算法求解原問題。再次期間遞歸調用會繼而求解小規模問題。
這裏寫圖片描述

此算法可以改進,因此它會多次重複的計算規模更小的子問題。解法方法是引入備忘錄機制,當 i<n 時,最大收益被計算ri ,就保存起來,下次計算到的時候,直接查表引用,不必再進行遞歸計算。

//直接遞歸計算
//int cut_rod(int p[],int n)
//{
//  if(n==0)
//      return 0;
//  int q=-1;
//  for(int i=1;i<=n;i++)
//  {
//      int temp=p[i]+cut_rod(p,n-i);
//      if(q<temp)
//      {
//          q=temp;
//      }
//  }
//  return q;
//}

//帶備忘錄:先定義一個數組存放計算過的收益,此數組不能放到遞歸裏。
//int  Memoized_cut_Rod(int p[],int n)
//{
//  vector<int>r(n,-1);
//  return Memoized_cut_Rod_Aux(p,n,r);
//}
//int Memoized_cut_Rod_Aux(int p[],int n,vector<int>r)
//{
//  int q=-1;
//  if(r[n]>=0)
//      return r[n];
//  if(n==0)
//      q=0;
//  else
//  {
//      for(int i=1;i<=n;i++)
//      {
//          int temp=p[i]+Memoized_cut_Rod_Aux(p,n-i,r);
//          if(q<temp)
//          {
//              q=temp;
//          }
//      }
//      r[n]=q;
//  }
//  return q;
//
//}

自底向上法求解小規模問題
自底向上法是直接先求解小規模問題,在小規模問題上逐步求解大規模問題。

//int Bottom_up_cut_rod(int p[],int n)
//{
//  vector<int>r;//保存切割的最優值
//  vector<int>s;//保存切割點
//  r.push_back(0);
//  s.push_back(0);
//  for(int j=1;j<=n;j++)//逐步求解規模j的問題,一直求解到n,即原問題
//  {
//      int q=-1;
//      for(int i=1;i<=j;i++)
//      {
//          int temp=p[i]+r[j-i];
//          if(q<temp)
//          {
//              q=temp;
//              s.push_back(i);
//          }
//      }
//      r.push_back(q);
//  }
//  return r[n];
//}
//

實例計算

int main()
//{
//  int p[]={0,1,5,8,9,10,17,17,20,24,30};
//  cout<<cut_rod(p,5)<<endl;
//  cout<<Memoized_cut_Rod(p,5)<<endl;
//  cout<<Bottom_up_cut_rod(p,5)<<endl;
//  getchar();
//  
//}

2 矩陣鏈相乘問題

給定n個矩陣序列<A1,...,An> ,如何加括號明確計算次序,進行更優的計算。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章