算法设计与分析课程复习笔记7——动态规划

算法设计与分析课程复习笔记7——动态规划

动态规划

  • 和分治法一样,是一种算法设计技术。
  • 子问题非独立。
  • 分治法通过递归方式解决性质相同的子问题,
    而动态规划每次解决一个子问题,并将结果存储在表格中。
  • 用于优化类问题。

算法:

  1. 描述最优解的结构特征
  2. 定义最优解决方案的递归形式
  3. 以自底向上的方式计算最优解决方案的值
  4. 从计算信息构造出最优解决方案

装配线排程

装配线排程
S 1 , 1 , S 1 , 2 , , S 1 , n S 2 , 1 , S 2 , 2 , , S 2 , n S_{1,1},S_{1,2},……,S_{1,n};S_{2,1},S_{2,2},……,S_{2,n} 为两条装配线的工序站台
a 1 , 1 , a 1 , 2 , , a 1 , n a 2 , 1 , a 2 , 2 , , a 2 , n a_{1,1},a_{1,2},……,a_{1,n};a_{2,1},a_{2,2},……,a_{2,n} 为两条装配线的各站台工作时间
每条装配线的第j个站台的功能相同,但是效率不一致,即花费时间不同。
另外有上线时间 e 1 , e 2 e_1,e_2 和下线时间 x 1 , x 2 x_1,x_2
以及从一条装配线变换到另一条装配线需要的时间 t 1 , 1 , t 1 , 2 , , t 1 , n 1 t 2 , 1 , t 2 , 2 , , t 2 , n 1 t_{1,1},t_{1,2},……,t_{1,n-1};t_{2,1},t_{2,2},……,t_{2,n-1}

问题:如何充分利用两条装配线,使得组装一辆汽车的时间最短?

解决方法:
1️⃣蛮力法
计算装配线排程所有可能的组合情况,比较并选择出最短时间的组合
2️⃣动态规划
【1】.构建最优解
考虑所有从起点到达 S 1 , j S_{1,j} 可能途径
只有两种可能:
①从 S 1 , j 1 S_{1,j-1} 直接到 S 1 , j S_{1,j}
②从 S 2 , j 1 S_{2,j-1} 花费 t 2 , j 1 t_{2,j-1} 时间转换到 S 1 , j S_{1,j}
构建最优解
如果到达 S 1 , j S_{1,j} 的最快装配路线来自 S 1 , j 1 S_{1,j-1} 那么必须是从装配线起点经过 S 1 , j 1 S_{1,j-1} 的最快装配路线。 S 2 , j 1 S_{2,j-1} 同理分析。

最优解的结构
寻求从起点到达 S 1 , j S_{1,j} 最快装配路线,可分解为寻求从起点经过 S 1 , j 1 S_{1,j-1} or S 2 , j 1 S_{2,j-1} 最快装配路线问题。
我们将这种具有分解递归特征的解的形式称为最优化结构特征
利用这种优化构造特征,从子问题的最优化解获得整个问题的最优化的解。

【2】.递归解
利用子问题的最优解,通过递归的方式求解原问题的最优解
f f* 为完成所有装配过程的最短时间。
f i [ j ] f_i[j] 表示从起点经过Si,j工序的最短时间.

f = m i n ( f 1 [ n ] + x 1 , f 2 [ n ] + x 2 ) f* = min (f_1[n] + x_1, f_2[n] + x_2)

j = 1 j=1
f 1 [ 1 ] = e 1 + a 1 , 1 f_1[1] = e_1 + a_{1,1}
f 2 [ 1 ] = e 2 + a 2 , 1 f_2[1] = e_2 + a_{2,1}

j 2 j≥2
f 1 [ j ] = m i n ( f 1 [ j 1 ] + a 1 , j , f 2 [ j 1 ] + t 2 , j 1 + a 1 , j ) f_1[j] = min(f_1[j - 1] + a_{1,j} ,f_2[j -1] + t_{2,j-1} + a_{1,j})
f 2 [ j ] = m i n ( f 2 [ j 1 ] + a 2 , j , f 1 [ j 1 ] + t 1 , j 1 + a 2 , j ) f_2[j] = min(f_2[j - 1] + a_{2,j} ,f_1[j -1] + t_{1,j-1} + a_{2,j})

【3】.计算最优解
如果自顶向下求最优解:
自顶向下
那么将导致指数增长的计算时间。

所以我们选择按 j j 递增,即自底向上的方式求解。
自底向上
【4】.构建最优方案
最优排程序列
最优解
算法:
FastestWay(a,t,e,x,n)
  f 1 [ 1 ] e 1 + a 1 , 1 f_1[1] \leftarrow e_1+a_{1,1}
  f 2 [ 1 ] e 2 + a 2 , 1 f_2[1] \leftarrow e_2+a_{2,1}
 for j=2 to n
  do if f 1 [ j 1 ] + a 1 , j f_1[j-1]+a_{1,j} f 2 [ j 1 ] + t 2 , j 1 + a 1 , j f_2[j-1]+t_{2,j-1}+a_{1,j}
   then f 1 [ j ] f 1 [ j 1 ] + a 1 , j f_1[j] \leftarrow f_1[j-1]+a_{1,j}
      I 1 [ j ] 1 I_1[j] \leftarrow 1
   else f 1 [ j ] f 2 [ j 1 ] + t 2 , j 1 + a 1 , j f_1[j] \leftarrow f_2[j-1]+t_{2,j-1}+a_{1,j}
      I 1 [ j ] 2 I_1[j] \leftarrow 2
   if f 2 [ j 1 ] + a 2 , j f_2[j-1]+a_{2,j} f 1 [ j 1 ] + t 1 , j 1 + a 2 , j f_1[j-1]+t_{1,j-1}+a_{2,j}
   then f 2 [ j ] f 2 [ j 1 ] + a 2 , j f_2[j] \leftarrow f_2[j-1]+a_{2,j}
      I 1 [ j ] 2 I_1[j] \leftarrow 2
   else f 2 [ j ] f 1 [ j 1 ] + t 1 , j 1 + a 2 , j f_2[j] \leftarrow f_1[j-1]+t_{1,j-1}+a_{2,j}
      I 1 [ j ] 1 I_1[j] \leftarrow 1
 if f 1 [ n ] + x 1 f 2 [ n ] + x 2 f_1[n]+x_1 ≤ f_2[n] + x_2
  then f = f 1 [ n ] + x 1 f* = f_1[n]+x_1
     I = 1 I* = 1
  else f = f 2 [ n ] + x 2 f* = f_2[n]+x_2
     I = 2 I* = 2

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

最优排程

矩阵链相乘

给定矩阵序列 A 1 , A 2 , , A n A_1, A_2, …, A_n ,求它们的积
C = A B C=A*B
c o l A = r o w B col_A=row_B
r o w C = r o w A row_C=row_A
c o l C = c o l B col_C=col_B
A 1 , A 2 , , A n A_1, A_2, …, A_n
c o l i = r o w i + 1 col_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]

A 1 ,     A 2 ,   ,   A n A_1,   A_2, ……,  A_n
p 0 p 1 , p 1 p 2 , p n 1 p n p_0*p_1,p_1*p_2,……,p_{n-1}*p_n

如何决定矩阵链相乘的顺序,即如何放置括号,使矩阵链相乘所需要的数量乘法的次数最小
1️⃣蛮力法
逐一比较
2️⃣动态规划
【1】.最优矩阵链相乘顺序结构
标记 A i j A_{i…j} = A i , A i + 1 , , A j A_i,A_{i+1},……,A_j = A i k A k + 1 j A_{i…k}A_{k+1…j}

假设矩阵链 A i j A_{i…j} 相乘的最优顺序在 A k A_k A k + 1 A_{k+1} 分割

【2】.递归解
A i j A_{i…j} 数量乘法的次数最小的运算顺序
利用m[i, j]标记 A i j A_{i…j} 最小的数量乘法次数


i f   i = j if i=j
m [ i , j ] = 0 m[i,j]=0
i f   i < j if i<j
m [ i , j ] = m i n i k j { m [ i , k ] + m [ k + 1 , j ] + p i 1 p k p j } 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] + p I 1 p k p j p_{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]:记录了 A i A i + 1 A j A_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 A i A_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的最长共同子序列为 Z Z&#x27; =(B, D, A, B)

解决方法
1️⃣蛮力法
穷举X的所有子序列,检查其是否在Y中出现,然后选出LCS
2️⃣动态规划
【1】.最优解结构
X = ( x 1 , x 2 , x m ) X=(x_1,x_2,……,x_m)
Y = ( y 1 , y 2 , y n ) Y=(y_1,y_2,……,y_n)
L C S = Z = ( z 1 , z 2 , z k ) LCS=Z=(z_1,z_2,……z_k)

如果 x m = y n x_m=y_n ,那么 z k = x m = y n z_k=x_m=y_n , Z k 1 Z_{k-1} X m 1 X_{m-1} Y n 1 Y_{n-1} 的LCS
如果 x m x_m y n y_n ,那么 z k z_k x m x_m 就意味着 Z Z X m 1 X_{m-1} Y Y 的LCS
如果 x m x_m y n y_n ,那么 z k z_k y n y_n 就意味着 Z Z X X Y n 1 Y_{n-1} 的LCS

【2】.递归解
C:X 和Y最长共同子序列的长度
c[i,j]: X i X_i Y j Y_j 最长共同子序列的长度
问题的解即为c[m,n]

c [ i , j ] = { 0 ,   i f   i = 0   o r   j = 0 c [ i 1 , j 1 ] + 1 ,   i f   x i = y j , i , j &gt; 0 m a x ( c [ i , j 1 ] , c [ i 1 , j ] ) ,   i f   x i y j , 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 x i x_i = y j y_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 ( m n ) O(mn)

【4】.构建最长共同子序列
最长共同子序列

参考:任课教师邱德红教授的课件

发布了25 篇原创文章 · 获赞 19 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42605042/article/details/89761105
今日推荐