设从矩阵Ai 到 Aj 的矩阵序列为 A[i:j] , m[][] 存放最小乘法次数 ,自底向上求解求解 , 即从子链长度为1 逐步求解子链长度为n的解
当 i==j 时 , 不需要乘 , m[i][i] = 0
- 自底向上求解问题的解 ,
- 当子链长度为1的时候无需求解 , 及m[i][i] = 0
- 自底向上求解问题的解 ,
当i != j时候, 需要根据子问题的解来计算当前解
- m[i:j] = MIN{ m[i:k] +m[k+1] + ppp| k∈[i,j) }
- 尝试当前子链A[i:j]的所有断点(遍历) , 获得当前问题的最优解
- m[i:k] , 该子链长度小于m[i:j] 的长度 , 所以此时一定已经存在m[i:k]最优解
- m[k+1:j] , 同上当前就是最优解
- m[i:j] = MIN{ m[i:k] +m[k+1] + ppp| k∈[i,j) }
/*矩阵连乘问题-动态规划*/#include<stdio.h>#include<stdlib.h>#include<time.h>//矩阵最大行/列 数const int MAXSIZE = 101;//矩阵最小的行/列 数const int MINSIZE = 2;//存放最优问题的断点int s[MAXSIZE][MAXSIZE];//存放子问题结果int m[MAXSIZE][MAXSIZE];//最多的矩阵的个数+1const int MNUM = 3;//存放可连乘矩阵的所有行列下标 , 由于 上一个矩阵的列等于下一个矩阵的行数//故第n个矩阵的 行数为p[n-1] 列数为p[n]int p[MNUM+1];int tt = 0;//输出问题解 可以省略最高维度的大小void printres(int l, int r, int s[][MAXSIZE],int flag) {if (l == r) {printf("%d:%d", p[l - 1], p[l]);return;}//printf("%d %d\n", l, r);//system("pause");if (flag) {printf("(");printres(l, s[l][r], s,0);printf(")(");printres(s[l][r] + 1, r, s,0);printf(")");}else {printf("[");printres(l, s[l][r], s,1);printf("][");printres(s[l][r] + 1, r, s,1);printf("]");}}//动归解决问题void solve() {//A[i][i] 的乘法次数为0for (int i = 1; i <= MNUM; i++) {m[i][i] = 0;}//矩阵连乘子链的长度从2增长for (int r = 2; r <= MNUM; r++) {//i为r长度子链的起始下标for (int i = 1; i <= MNUM - r + 1;i++) {//j为r长度子链的尾下标int j = i + r - 1;//k ∈[i:j)//先计算k = i 时的计算次数m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];s[i][j] = i;for (int k = i + 1; k < j; k++) {int temp = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];if (temp < m[i][j]) {s[i][j] = k;m[i][j] = temp;}}}}}int main(){while (1){srand(time(NULL));for (int i = 0; i <= MNUM; i++) {//确定每个矩阵的行列数p[i] = (rand() % (MAXSIZE - MINSIZE))+MINSIZE;printf("%d ", p[i]);}printf("\n");/*p[0] = 10;p[1] = 100;p[2] = 5;p[3] = 50;for (int i = 0; i <= MNUM; i++) {printf("%d ", p[i]);}printf("\n");*/solve();printres(1, MNUM, s,1);printf("最小乘法次数为 : %d\n", m[1][MNUM]);system("pause");}return 0;}/*p[0] - p[3] = 10 100 5 50*/
