动态规划算法的基本要素
(1):最优子结构性质
(2):重叠子问题性质
动态规划法解题思路
(1):找出最优解的性质,并刻画其结构特征
(2):递归的定义最优值
(3):以自底向上的方式计算出最优值
(4):根据计算最优值得到的信息,构造最优解
动态规划与分治的主要区别
(1):分治的自顶向下进行计算的,动态规划是自底向上进行计算的
(2):动态规划法记录了已解决的子问题的解,分治法不记录
矩阵连乘问题的描述
给定N个矩阵A1,A2…An,其中,A(i)和A(i+1)是可乘的,确定计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少
解决思路
1:将N个矩阵的行列数存入一个大小为N+1的一维数组A中,即:A[0]为第一个矩阵的行数,A[1]为第一个矩阵的列数,又因为第一二个矩阵是可乘的,所以同时又是第二个矩阵的行数,依次存入N个矩阵的行列数
申请一个规格为(N+1) (N+1)的二维数组M用以记录动态规划中的一步步所得的子问题的解,规格为N+1是因为便于在填表时方便易懂。第0行,第0列不填。
再申请一个此规格的二维数组S,用以存储得出的最优子结构的分割点
2:我们再来详细解释一下1中的二维数组M的意义,M[i][j]的意义则代表从第i个矩阵乘到第j个矩阵所乘的最小次数,所以,我们最终所需的结果便是M[1][6]。
由上述亦可得,M表沿对角线左下部分是无用的,对角线上M[i][i]=0,S表亦是。
填完对角线的所有0之后,我们可以考虑填沿对角线向右上方向上的一层,比如M[1][2],M[2][3],M[3][4]…这些我们都可以直接填,因为,它们没有其他解可以比较
沿右上方向,我们再走一层,此时,我们考虑M[1][3],这时,我们知道我们可以(A1 A2) A3 即当2做cut点时,也可以A1 (A2 A3) 即当1做cut点时 。这时我们将这两种情况所得结果比较,取得最小次数存入。
这两种情况的结果如何得到呢?我们可以有这样的公式(当k为cut点时)`times=M[i][k] + M[k+1][j] + A[i-1] A[k] * A[j]`
这样,我们就可以依次填表,最后得到了M[1][N]
C代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #include <stdio.h> #include <stdlib.h> #include <string.h> int Matrix(int *A,int **M,int **S,int n) { int i,l,j,k,q; for(i = 1;i < n; i++){ //将对角线置为0 M[i][i] = 0; } for(l = 2;l < n; l++){ //第一层循环,从对角线向右上方向推进 for(i = 1;i <= n - l; i++) //第二层循环,从左上至右下填写 { j = i + l -1; M[i][j] = 999999; //将此值初始为很大的值,便于下面的比较 for(k = i ;k <= j -1; k++){ //第三层循环,列出所有有可能作为cut点的情况并计算结果 q = M[i][k] + M[k+1][j] + A[i-1] * A[k] * A[j]; if (q < M[i][j]){ M[i][j] = q; //再一次次比较中找出最小次数的情况 S[i][j] = k; //并将cut点存入S表作以记录 } } } } return 0; } int PrintMatrix(int **S,int i, int j) //依据S表打印结果,思想为递归 { if (i == j){ printf("A%d",i); } else{ printf("("); PrintMatrix(S,i,S[i][j]); PrintMatrix(S,S[i][j] + 1,j); printf(")"); } return 0; } int main() { int A[] = {30,35,15,5,10,20,25}; int i,j; int n = sizeof(A) / sizeof(int) ; int **M = (int **)malloc(sizeof(int *) * n); //申请二维数组 for(i = 0; i < n; i++){ M[i] = (int*)malloc(sizeof(int) * n); } int **S = (int **)malloc(sizeof(int *) * n); for(i = 0; i < n; i++){ S[i] = (int*)malloc(sizeof(int) * n); } printf("\n"); Matrix(A,M,S,n); //调用函数 for ( i = 0; i < n; i++ ){ //打印M表 for( j = 0; j < n; j++ ){ printf("%5d ",M[i][j]); } printf("\n"); } printf("==============================================================\n"); for ( i = 0; i < n; i++ ){ //打印S表 for( j = 0; j < n; j++ ){ printf("%5d",S[i][j]); } printf("\n"); } PrintMatrix(S,1,6); //显示结果 printf("\n"); return 0; } |
实现结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 ============================================================== 0 0 0 0 0 0 0 0 0 1 1 3 3 3 0 0 0 2 3 3 3 0 0 0 0 3 3 3 0 0 0 0 0 4 5 0 0 0 0 0 0 5 0 0 0 0 0 0 0 ((A1(A2A3))((A4A5)A6)) |
感谢阅读,欢迎指正。