算法设计与分析课程复习笔记7——动态规划
动态规划
和分治法一样,是一种算法设计技术。
子问题非独立。
分治法通过递归方式解决性质相同的子问题, 而动态规划每次解决一个子问题,并将结果存储在表格中。
用于优化类问题。
算法:
描述最优解的结构特征
定义最优解决方案的递归形式
以自底向上的方式计算最优解决方案的值
从计算信息构造出最优解决方案
装配线排程
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}
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}
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
e 1 , e 2 和下线时间
x
1
,
x
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}
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 可能途径 只有两种可能: ①从
S
1
,
j
−
1
S_{1,j-1}
S 1 , j − 1 直接到
S
1
,
j
S_{1,j}
S 1 , j ②从
S
2
,
j
−
1
S_{2,j-1}
S 2 , j − 1 花费
t
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}
S 1 , j 的最快装配路线来自
S
1
,
j
−
1
S_{1,j-1}
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 2 , j − 1 同理分析。
最优解的结构 寻求从起点到达
S
1
,
j
S_{1,j}
S 1 , j 最快装配路线,可分解为寻求从起点经过
S
1
,
j
−
1
S_{1,j-1}
S 1 , j − 1 or
S
2
,
j
−
1
S_{2,j-1}
S 2 , j − 1 最快装配路线问题。 我们将这种具有分解递归特征的解的形式称为最优化结构特征 。 利用这种优化构造特征,从子问题的最优化解获得整个问题的最优化的解。
【2】.递归解 利用子问题的最优解,通过递归的方式求解原问题的最优解
f
∗
f*
f ∗ 为完成所有装配过程的最短时间。
f
i
[
j
]
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)
f ∗ = m i n ( f 1 [ n ] + x 1 , f 2 [ n ] + x 2 )
当
j
=
1
j=1
j = 1 时
f
1
[
1
]
=
e
1
+
a
1
,
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}
f 2 [ 1 ] = e 2 + a 2 , 1
当
j
≥
2
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 1 [ j ] = m i n ( 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})
f 2 [ j ] = m i n ( f 2 [ j − 1 ] + a 2 , j , f 1 [ j − 1 ] + t 1 , j − 1 + a 2 , j )
【3】.计算最优解 如果自顶向下求最优解: 那么将导致指数增长的计算时间。
所以我们选择按
j
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 1 [ 1 ] ← e 1 + a 1 , 1
f
2
[
1
]
←
e
2
+
a
2
,
1
f_2[1] \leftarrow e_2+a_{2,1}
f 2 [ 1 ] ← 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 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}
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}
f 1 [ j ] ← f 1 [ j − 1 ] + a 1 , j
I
1
[
j
]
←
1
I_1[j] \leftarrow 1
I 1 [ j ] ← 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}
f 1 [ j ] ← f 2 [ j − 1 ] + t 2 , j − 1 + a 1 , j
I
1
[
j
]
←
2
I_1[j] \leftarrow 2
I 1 [ j ] ← 2 if
f
2
[
j
−
1
]
+
a
2
,
j
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}
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}
f 2 [ j ] ← f 2 [ j − 1 ] + a 2 , j
I
1
[
j
]
←
2
I_1[j] \leftarrow 2
I 1 [ j ] ← 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}
f 2 [ j ] ← f 1 [ j − 1 ] + t 1 , j − 1 + a 2 , j
I
1
[
j
]
←
1
I_1[j] \leftarrow 1
I 1 [ j ] ← 1 if
f
1
[
n
]
+
x
1
≤
f
2
[
n
]
+
x
2
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
f ∗ = f 1 [ n ] + x 1
I
∗
=
1
I* = 1
I ∗ = 1 else
f
∗
=
f
2
[
n
]
+
x
2
f* = f_2[n]+x_2
f ∗ = f 2 [ n ] + x 2
I
∗
=
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]
I i [ j ] print “line” i “,station” j-1
矩阵链相乘
给定矩阵序列
A
1
,
A
2
,
…
,
A
n
A_1, A_2, …, A_n
A 1 , A 2 , … , A n ,求它们的积
C
=
A
∗
B
C=A*B
C = A ∗ B
c
o
l
A
=
r
o
w
B
col_A=row_B
c o l A = r o w B
r
o
w
C
=
r
o
w
A
row_C=row_A
r o w C = r o w A
c
o
l
C
=
c
o
l
B
col_C=col_B
c o l C = c o l B
A
1
,
A
2
,
…
,
A
n
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}
c o l i = r o w 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
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
p 0 ∗ p 1 , p 1 ∗ p 2 , … … , p n − 1 ∗ p n
如何决定矩阵链相乘的顺序,即如何放置括号,使矩阵链相乘所需要的数量乘法的次数最小 1️⃣蛮力法 逐一比较 2️⃣动态规划 【1】.最优矩阵链相乘顺序结构 标记
A
i
…
j
A_{i…j}
A i … j =
A
i
,
A
i
+
1
,
…
…
,
A
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 … k A k + 1 … j
假设矩阵链
A
i
…
j
A_{i…j}
A i … j 相乘的最优顺序在
A
k
A_k
A k 和
A
k
+
1
A_{k+1}
A k + 1 分割
【2】.递归解 求
A
i
…
j
A_{i…j}
A i … j 数量乘法的次数最小的运算顺序 利用m[i, j]标记
A
i
…
j
A_{i…j}
A i … j 最小的数量乘法次数
则
i
f
i
=
j
if i=j
i f i = j
m
[
i
,
j
]
=
0
m[i,j]=0
m [ i , j ] = 0
i
f
i
<
j
if i<j
i f 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\}
m [ i , j ] = m i n i ≤ k ≤ j { m [ i , k ] + m [ k + 1 , j ] + p i − 1 p k p 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
p I − 1 p k p 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
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
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'
Z ′ =(B, D, A, B)
解决方法 1️⃣蛮力法 穷举X的所有子序列,检查其是否在Y中出现,然后选出LCS 2️⃣动态规划 【1】.最优解结构
X
=
(
x
1
,
x
2
,
…
…
,
x
m
)
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)
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)
L C S = Z = ( z 1 , z 2 , … … z k )
如果
x
m
=
y
n
x_m=y_n
x m = y n ,那么
z
k
=
x
m
=
y
n
z_k=x_m=y_n
z k = x m = y n ,
Z
k
−
1
Z_{k-1}
Z k − 1 是
X
m
−
1
X_{m-1}
X m − 1 和
Y
n
−
1
Y_{n-1}
Y n − 1 的LCS 如果
x
m
x_m
x m ≠
y
n
y_n
y n ,那么
z
k
z_k
z k ≠
x
m
x_m
x m 就意味着
Z
Z
Z 是
X
m
−
1
X_{m-1}
X m − 1 和
Y
Y
Y 的LCS 如果
x
m
x_m
x m ≠
y
n
y_n
y n ,那么
z
k
z_k
z k ≠
y
n
y_n
y n 就意味着
Z
Z
Z 是
X
X
X 和
Y
n
−
1
Y_{n-1}
Y n − 1 的LCS
【2】.递归解 C:X 和Y最长共同子序列的长度 c[i,j]:
X
i
X_i
X i 和
Y
j
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
>
0
m
a
x
(
c
[
i
,
j
−
1
]
,
c
[
i
−
1
,
j
]
)
,
i
f
x
i
≠
y
j
,
i
,
j
>
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>0\\ max(c[i,j-1],c[i-1,j]), if x_i \neq y_j,i,j>0 \end{aligned} \right.
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 > 0 m a x ( c [ i , j − 1 ] , c [ i − 1 , j ] ) , i f x i ̸ = y j , i , j > 0
【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
x i =
y
j
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)
O ( m n )
【4】.构建最长共同子序列
参考:任课教师邱德红教授的课件