算法設計與分析課程複習筆記7——動態規劃

算法設計與分析課程複習筆記7——動態規劃

動態規劃

  • 和分治法一樣,是一種算法設計技術。
  • 子問題非獨立。
  • 分治法通過遞歸方式解決性質相同的子問題,
    而動態規劃每次解決一個子問題,並將結果存儲在表格中。
  • 用於優化類問題。

算法:

  1. 描述最優解的結構特徵
  2. 定義最優解決方案的遞歸形式
  3. 以自底向上的方式計算最優解決方案的值
  4. 從計算信息構造出最優解決方案

裝配線排程

裝配線排程
S1,1,S1,2,,S1,nS2,1,S2,2,,S2,nS_{1,1},S_{1,2},……,S_{1,n};S_{2,1},S_{2,2},……,S_{2,n}爲兩條裝配線的工序站臺
a1,1,a1,2,,a1,na2,1,a2,2,,a2,na_{1,1},a_{1,2},……,a_{1,n};a_{2,1},a_{2,2},……,a_{2,n}爲兩條裝配線的各站臺工作時間
每條裝配線的第j個站臺的功能相同,但是效率不一致,即花費時間不同。
另外有上線時間e1,e2e_1,e_2和下線時間x1,x2x_1,x_2
以及從一條裝配線變換到另一條裝配線需要的時間t1,1,t1,2,,t1,n1t2,1,t2,2,,t2,n1t_{1,1},t_{1,2},……,t_{1,n-1};t_{2,1},t_{2,2},……,t_{2,n-1}

問題:如何充分利用兩條裝配線,使得組裝一輛汽車的時間最短?

解決方法:
1️⃣蠻力法
計算裝配線排程所有可能的組合情況,比較並選擇出最短時間的組合
2️⃣動態規劃
【1】.構建最優解
考慮所有從起點到達S1,jS_{1,j}可能途徑
只有兩種可能:
①從S1,j1S_{1,j-1}直接到S1,jS_{1,j}
②從S2,j1S_{2,j-1}花費t2,j1t_{2,j-1}時間轉換到S1,jS_{1,j}
構建最優解
如果到達S1,jS_{1,j}的最快裝配路線來自S1,j1S_{1,j-1}那麼必須是從裝配線起點經過S1,j1S_{1,j-1}的最快裝配路線。S2,j1S_{2,j-1}同理分析。

最優解的結構
尋求從起點到達S1,jS_{1,j}最快裝配路線,可分解爲尋求從起點經過S1,j1S_{1,j-1} or S2,j1S_{2,j-1} 最快裝配路線問題。
我們將這種具有分解遞歸特徵的解的形式稱爲最優化結構特徵
利用這種優化構造特徵,從子問題的最優化解獲得整個問題的最優化的解。

【2】.遞歸解
利用子問題的最優解,通過遞歸的方式求解原問題的最優解
ff*爲完成所有裝配過程的最短時間。
fi[j]f_i[j]表示從起點經過Si,j工序的最短時間.

f=min(f1[n]+x1,f2[n]+x2)f* = min (f_1[n] + x_1, f_2[n] + x_2)

j=1j=1
f1[1]=e1+a1,1f_1[1] = e_1 + a_{1,1}
f2[1]=e2+a2,1f_2[1] = e_2 + a_{2,1}

j2j≥2
f1[j]=min(f1[j1]+a1,j,f2[j1]+t2,j1+a1,j)f_1[j] = min(f_1[j - 1] + a_{1,j} ,f_2[j -1] + t_{2,j-1} + a_{1,j})
f2[j]=min(f2[j1]+a2,j,f1[j1]+t1,j1+a2,j)f_2[j] = min(f_2[j - 1] + a_{2,j} ,f_1[j -1] + t_{1,j-1} + a_{2,j})

【3】.計算最優解
如果自頂向下求最優解:
自頂向下
那麼將導致指數增長的計算時間。

所以我們選擇按jj遞增,即自底向上的方式求解。
自底向上
【4】.構建最優方案
最優排程序列
最優解
算法:
FastestWay(a,t,e,x,n)
 f1[1]e1+a1,1f_1[1] \leftarrow e_1+a_{1,1}
 f2[1]e2+a2,1f_2[1] \leftarrow e_2+a_{2,1}
 for j=2 to n
  do if f1[j1]+a1,jf_1[j-1]+a_{1,j}f2[j1]+t2,j1+a1,jf_2[j-1]+t_{2,j-1}+a_{1,j}
   then f1[j]f1[j1]+a1,jf_1[j] \leftarrow f_1[j-1]+a_{1,j}
      I1[j]1I_1[j] \leftarrow 1
   else f1[j]f2[j1]+t2,j1+a1,jf_1[j] \leftarrow f_2[j-1]+t_{2,j-1}+a_{1,j}
      I1[j]2I_1[j] \leftarrow 2
   if f2[j1]+a2,jf_2[j-1]+a_{2,j}f1[j1]+t1,j1+a2,jf_1[j-1]+t_{1,j-1}+a_{2,j}
   then f2[j]f2[j1]+a2,jf_2[j] \leftarrow f_2[j-1]+a_{2,j}
      I1[j]2I_1[j] \leftarrow 2
   else f2[j]f1[j1]+t1,j1+a2,jf_2[j] \leftarrow f_1[j-1]+t_{1,j-1}+a_{2,j}
      I1[j]1I_1[j] \leftarrow 1
 if f1[n]+x1f2[n]+x2f_1[n]+x_1 ≤ f_2[n] + x_2
  then f=f1[n]+x1f* = f_1[n]+x_1
    I=1I* = 1
  else f=f2[n]+x2f* = f_2[n]+x_2
    I=2I* = 2

PrintStation(I,n)
 i ← I*
 print “line” i “,station” n
 for j ← n downto 2
  do i ←Ii[j]I_i[j]
  print “line” i “,station” j-1

最優排程

矩陣鏈相乘

給定矩陣序列A1,A2,,AnA_1, A_2, …, A_n,求它們的積
C=ABC=A*B
colA=rowBcol_A=row_B
rowC=rowArow_C=row_A
colC=colBcol_C=col_B
A1,A2,,AnA_1, A_2, …, A_n
coli=rowi+1col_i = row_{i+1}

矩陣鏈相乘的順序極大的影響計算的代價

MatrixMultiply(A,B)
 if columns[A] ≠ rows[B]
  then error “incompatible dimensions”
  else for i ← 1 to rows[A]
     do for j ← 1 to columns[B]
      do C[i,j]=0
        for k ← 1 to columns[A]
         do C[i,j] ← C[i,j] + A[i,k]B[k.j]

A1,  A2, , AnA_1,   A_2, ……,  A_n
p0p1,p1p2,pn1pnp_0*p_1,p_1*p_2,……,p_{n-1}*p_n

如何決定矩陣鏈相乘的順序,即如何放置括號,使矩陣鏈相乘所需要的數量乘法的次數最小
1️⃣蠻力法
逐一比較
2️⃣動態規劃
【1】.最優矩陣鏈相乘順序結構
標記AijA_{i…j}=Ai,Ai+1,,AjA_i,A_{i+1},……,A_j=AikAk+1jA_{i…k}A_{k+1…j}

假設矩陣鏈AijA_{i…j}相乘的最優順序在AkA_kAk+1A_{k+1}分割

【2】.遞歸解
AijA_{i…j}數量乘法的次數最小的運算順序
利用m[i, j]標記AijA_{i…j}最小的數量乘法次數


if i=jif i=j
m[i,j]=0m[i,j]=0
if i<jif i<j
m[i,j]=minikj{m[i,k]+m[k+1,j]+pi1pkpj}m[i,j]=min_{i≤k≤j}\{m[i,k]+m[k+1,j]+p_{i-1}p_kp_j\}

動態規劃的適用性

  • 最優解包含子問題的最優解
  • 遞歸算法一次又一次地重複同樣的問題;只有Θ(n2)個子問題。

【3】.計算解
Matrix-Chain-Order(p)
 n ← length[p]-1;
 for i ← 1 to n
  m[i, i] ← 0;
 for I ← 2 to n
  for i ← 1 to n – l +1
   j ← i + l -1;
   m[i, j] ← \infty;
   for k ← i to j -1
    q ← m[i, k] + m[k+1, j] + pI1pkpjp_{I-1}p_kp_j;
    if q < m[i, j]
     m[i,j] ← q;
     s[i, j] ← k;
 return m and s

矩陣鏈相乘
【4】.構造最優相乘順序
s[i, j]:記錄了AiAi+1AjA_i A_{i+1} … A_j的最優分割順序位置

Matrix-Chain-Multiply(A, s, i, j)
 if j > i
  X ← Matrix-Chain-Multiply(A, s, i, s[i,j]);
  Y ← Matrix-Chain-Multiply(A, s, s[i, j]+1, j);
  return Matrix-Multiply(X, Y);
 else return AiA_i;

最長共同子序列LCS

Z =(B,C,A)是X,Y的一個共同子序列
X = (A,B,C,B,D,A,B)
Y = (B, D, C, A, B, A)
X,Y的最長共同子序列爲ZZ&#x27;=(B, D, A, B)

解決方法
1️⃣蠻力法
窮舉X的所有子序列,檢查其是否在Y中出現,然後選出LCS
2️⃣動態規劃
【1】.最優解結構
X=(x1,x2,xm)X=(x_1,x_2,……,x_m)
Y=(y1,y2,yn)Y=(y_1,y_2,……,y_n)
LCS=Z=(z1,z2,zk)LCS=Z=(z_1,z_2,……z_k)

如果xm=ynx_m=y_n,那麼zk=xm=ynz_k=x_m=y_n,Zk1Z_{k-1}Xm1X_{m-1}Yn1Y_{n-1}的LCS
如果xmx_myny_n,那麼zkz_kxmx_m就意味着ZZXm1X_{m-1}YY的LCS
如果xmx_myny_n,那麼zkz_kyny_n就意味着ZZXXYn1Y_{n-1}的LCS

【2】.遞歸解
C:X 和Y最長共同子序列的長度
c[i,j]:XiX_iYjY_j最長共同子序列的長度
問題的解即爲c[m,n]

c[i,j]={0, if i=0 or j=0c[i1,j1]+1, if xi=yj,i,j&gt;0max(c[i,j1],c[i1,j]), if xiyj,i,j&gt;0 c[i,j]=\left\{ \begin{aligned} 0, if i=0 or j=0\\ c[i-1,j-1]+1, if x_i=y_j,i,j&gt;0\\ max(c[i,j-1],c[i-1,j]), if x_i \neq y_j,i,j&gt;0 \end{aligned} \right.

【3】.計算解
LCS算法:
LCSlength(X,Y)
 m ← length(X)
 n ← length(Y)
 for i ← 1 to m
  c[i,0] ← 0
 for j ← 0 to n
  c[0,j] ← 0
 for i ← 1 to m
  for j ← 1 to n
   if xix_i=yjy_j
    c[i,j] ← c[i-1,j-1] + 1
    b[i,j] ← “↖”
   else if c[i-1,j] ≥ c[i,j-1]
      c[i,j] ← c[i-1,j]
      b[i,j] ← “↑”
     else c[i,j] ← c[i,j-1]
       b[i,j] ← “←”
 return c and b

算法分析:其實就是簡單的填表,一個格子的計算量爲O(1),總共m*n個格子,所以總計算開銷O(mn)O(mn)

【4】.構建最長共同子序列
最長共同子序列

參考:任課教師邱德紅教授的課件

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