基本要素:
(1)最优子结构性质
(2)重叠子问题性质
思想:
动态规划和分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
与分治法不同的是,动态规划法中分解得到的子问题不是互相独立的。若用分治法来解这类子问题,分解得到的子问题数目非常多,最后解决原问题需要耗费指数时间。但是这些子问题有很多是相同的,也就是同一个子问题被计算了很多次,不同子问题的数量可能只有多项式量级。
如果我们保存已经解决的子问题的解,需要解相同子问题时找出已经计算出的解,这样可以减少大量重复计算,最终得到多项式时间算法。
经常用一个表来记录所有已解决的子问题的解。不管该子问题以后是否被利用,只要它被计算过,就将其结果填入表中。这就是动态规划的基本思想。具体的动态规划算法多种多样,但它们具有相同的填表格式。
—(计算机算法设计与分析 第四版 王晓东)—
####动态规划例子:(矩阵连乘问题)
给定N个矩阵{A1,A2,A3,An},其中Ai与A(i+1)是可以相乘的,考察这N个矩阵的连乘积A1A2,An。
由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定,比如下面4个矩阵的连乘积。
A1,A2, A3, A4
1,(2,(3,4))
1,((2,3),4)
(1,2),(3,4)
(1,(2,3)),4
((1,2),3),4
#####最优解的结构
计算A[1:n]的最优次序所包含的计算矩阵子链A[1:k]和A[k+1:n]的次序也是最优的。
A[1:n] = A[1:k] * A[K+1:n] 其中 ( 1 < k < n)
递推关系如下:
m(i , j) = 0 ,(i=j)
m(i , j) = min{ m(i,k) + m(k+1,j) + P(i-1)P(k)P(j) } ,(i < j )
#####重叠子问题
重叠的子问题主要体现在m表格里,
例题:我们计算如下6个矩阵的连乘积,
A1 ------ A2 ------ A3 ----- A4 ----- A5 ----- A6
(3035) (3515) (155) (510) (1020) (2025)
const int N = 6;
int table[N + 1][N + 1];
int p[N + 1] = { 30, 35, 15, 5, 10, 20, 25 };
void MatrixMulti()
{for (int r = 2; r <= N; r++) //r表示连乘矩阵的个数{for (int i = 1; i <= N - r + 1; i++) //i表示起始矩阵索引{int j = i + r - 1; //j表示终止矩阵索引for (int k = i; k < j; k++){int temp = table[i][k] + table[k+1][j] + p[i - 1] * p[k] * p[j];table[i][j] = (table[i][j] == 0) ? temp : min(table[i][j], temp);}}}
}
int main()
{MatrixMulti();cout << "最小乘积为:" <<table[1][N] << endl;return 0;
}
/*输出结果:
最小乘积为:15125
table数组内容为:
0 0 0 0 0 0 0
0 0 15750 7875 9375 11875 15125
0 0 0 2625 4375 7125 10500
0 0 0 0 750 2500 5375
0 0 0 0 0 1000 3500
0 0 0 0 0 0 5000
0 0 0 0 0 0 0*/