动态规划DP,就是用分治的方法,但是记录下小问题的解,减少重复计算。
Fibonacci Numbers
问题描述
计算:T(N) = T(N-1) + T(N-2)
解法
1.令NextoLast = T(0), Next = T(1)
2.计算T(i) = NextToLast + Next
3.更新Next = NextToLast, NextToLast = T(i)
4.重复N次。
这个算法需要记录的只是最近的两次。
复杂度为O(N)
int Fibonacci ( int N )
{ int i, Last, NextToLast, Answer;
if ( N <= 1 ) return 1;
Last = NextToLast = 1; /* F(0) = F(1) = 1 */
for ( i = 2; i <= N; i++ ) {
Answer = Last + NextToLast; /* F(i) = F(i-1) + F(i-2) */
NextToLast = Last; Last = Answer; /* update F(i-1) and F(i-2) */
} /* end-for */
return Answer;
}
矩阵乘法
问题描述
对于矩阵 M 1 ⋅ M 2 ⋅ M 3.... M n M1\cdot M2 \cdot M3....M_n M1⋅M2⋅M3....Mn,求最小计算cost
已知对于矩阵 M ( i , j ) ⋅ M ( j , k ) M(i,j) \cdot M(j,k) M(i,j)⋅M(j,k),cost为 i ⋅ j ⋅ k i \cdot j\cdot k i⋅j⋅k
解法
令 m i , j = M i M i + 1 ⋅ M j m_{i,j} = M_iM_{i+1}\cdot M_j mi,j=MiMi+1⋅Mj, M i M_i Mi是 r i × r i − 1 r_i\times r_{i-1} ri×ri−1的矩阵
m
i
,
j
=
min
{
m
i
l
+
m
l
+
1
,
j
+
r
i
−
1
r
l
r
j
}
,
i
<
j
m_{i,j}=\min\{m_{il}+m_{l+1,j}+r_{i-1}r_lr_j\},i< j
mi,j=min{mil+ml+1,j+ri−1rlrj},i<j
m
i
.
i
=
0
m_{i.i}=0
mi.i=0
需要存的表(从下方开始算)是:
void OptMatrix( const long r[ ], int N, TwoDimArray M )
{ int i, j, k, L;
long ThisM;
for( i = 1; i <= N; i++ ) M[ i ][ i ] = 0;
for( k = 1; k < N; k++ ) /* k = j - i */
for( i = 1; i <= N - k; i++ ) { /* For each position */
j = i + k; M[ i ][ j ] = Infinity;
for( L = i; L < j; L++ ) {
ThisM = M[ i ][ L ] + M[ L + 1 ][ j ]
+ r[ i - 1 ] * r[ L ] * r[ j ];
if ( ThisM < M[ i ][ j ] ) /* Update min */
M[ i ][ j ] = ThisM;
} /* end for-L */
} /* end for-Left */
}
复杂度O(N3)
Optimal Binary Search Tree
问题描述
对于一颗BST,每个节点被搜索到的可能性为pi,求怎么改变根,使得达到最短的搜索时间。
注意,点的顺序是固定的。改变的只能是谁去当根。
最短的搜索时间是,该点到根的路径长度乘上该点的可能性,对所有点求和。
解法
i到j的cost,如果挑选l为根
ci,j=ci,l-1+cl+1,j+pi+…pj
简单一点来说i到j的cost,就是i到j里面挑一个点作为根,根到i和根到j的点组成左右子树,cost是左右子树cost和+i到j所有的点的搜索可能性之和
如果i=j,cost=pi
第二部分是一个常数。
对于上面这张表,存储了i到j范围中cost最小的值。记录下的根在计算下一个cost时没有用处,但是在最后看结果时有用。
比如计算break到do的cost
首先,所有的p加起来,是0.65是个常数,然后是左右子树cost查表,比如让char做根,就是查左树break到case和右子树do的cost
让break做根,左+右=0+0.66,
让case做根,左+右=0.22+0.3
让char做根,左+右=0.58+0.05
让do做根,左+右=1.02+0
最小的是case,0.52+0.65=1.17,填入break到do
算法对于i,j要遍历每一个元素。i*(n-i)*(n-i),一共N^3
复杂度为O(N3)
All-Pairs Shortest Path
问题描述
找到每一对点之间最短距离
解法
Dk[i][j]是长度小于等于k的路径中连接i,j的最短路径长度,DN-1[i][j]就是解。
D k [ i ] [ j ] = min { D k − 1 [ i ] [ j ] , D k − 1 [ i ] [ l ] + D k − 1 [ l ] [ j ] } D^k[i][j]=\min\{ D^{k-1}[i][j] , D^{k-1}[i][l] + D^{k-1}[l][j] \} Dk[i][j]=min{Dk−1[i][j],Dk−1[i][l]+Dk−1[l][j]}
算法是:首先在平面上找一个点,计算所有其他两个点i,j通过这个点的最短路径,然后更新i,j的最短路径。
然后更新这个点,注意顺序不能反了,因为这样会导致,计算i到k,j到k的距离不是最短的,更新出来没有意义。
O(N3)
Product Assembly
有两条线路,一辆车可以在站点换线。不同线路两个站点之间的时间不同。求总时间最小。
解法
用f[i][j]记录下到第i个站点,使用j线的时间。
f [ i ] [ 0 ] = min { f [ i − 1 ] [ 0 ] + t [ i ] [ 0 ] , f [ i − 1 ] [ 1 ] + c t [ i ] [ 1 ] } f[i][0]=\min\{f[i-1][0]+t[i][0],f[i-1][1]+ct[i][1]\} f[i][0]=min{f[i−1][0]+t[i][0],f[i−1][1]+ct[i][1]}
f [ i ] [ 1 ] = min { f [ i − 1 ] [ 1 ] + t [ i ] [ 1 ] , f [ i − 1 ] [ 0 ] + c t [ i ] [ 0 ] } f[i][1]=\min\{f[i-1][1]+t[i][1],f[i-1][0]+ct[i][0]\} f[i][1]=min{f[i−1][1]+t[i][1],f[i−1][0]+ct[i][0]}
解是min{f[n][0],f[n][1]}
O(N)空间和时间复杂度