算法导论15章 动态规划之矩阵链乘法问题

来源:互联网 发布:奥贵银软件下载 编辑:程序博客网 时间:2024/05/20 08:44

阵链乘法问题:

给定一个n个矩阵的序列(矩阵链)<A1, A2, A3, .……, An>,矩阵Ai的规模为Pi-1 * Pi, 求完全括号话方案,使得计算成绩A1*A2*......*An所需标量乘法次数最少。

注意:求解矩阵链乘法问题并不是要真正进行矩阵相乘运算,只是确定代价最低的计算顺序,确定最优计算书序所花费的时间通常要比随后真正进行矩阵相乘所节省的时间要少。

两个矩阵A、B相容,即A的列数等于B的行数时, 才能相乘。n个矩阵相乘有很多种计算方案,例如<A1, A2, A3, A4>

完全括号化的矩阵相乘链有

(A1(A2(A3 A4))

(A1((A2* A3)A4))

((A1 * A2)(A3* A4))

((A1(A2*A3)A4))

(((A1*A2)A3)A4)

但是每种相乘办法进行的乘法次数都不一样,这个问题即是是进行的乘法次数最少,求出分割点,并且给出最优化乘法链,运用的是自底向上的动态规划方法求解的

下面的两个m、s二维矩阵多用了一些空间,跟课本上的i, j标号保持了同步,便于理解,免去处理数组下标的很多问题。。。嘿嘿,有点偷懒....

#include <iostream>#include <vector>#include <algorithm>#include <limits.h>using namespace std;pair<vector<vector<int> >, vector<vector<int> >>matrixChainOrder(vector<int> p){    int n = p.size();//m[i][j]保存Ai...j的代价也是最优值vector<vector<int> > m(n, vector<int> (n, 0));    //s[i][j]记录m[i][j]最优解对应的分割点kvector<vector<int> > s(n, vector<int> (n, 0));//len是所求的矩阵链的长度for (int len = 2; len < n; len++){//计算m[i][j], i循环1...5for (int i = 1; i <= n-len; i++){int j = i+len-1;  //j是矩阵链的终点,(2, 6)m[i][j] = INT_MAX;//k:(i, j), 计算中间的代价for (int k = i; k < j; k++){//m[i][j]的代价为m[i][k]与m[k+1][j]//加上m[i][k]与m[k+1][j]的积(Ai,k与Ak+1,j的积为p[i-1]p[k]p[j])int q = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];if (q < m[i][j]){m[i][j] = q;s[i][j] = k;}}}}cout << "vector m:" << endl;for (int i = 0; i < n; i++){copy(m[i].begin(), m[i].end(), ostream_iterator<int>(cout, " "));    cout << endl;}cout << "vector s:" << endl;    for (int i = 0; i < n; i++){    copy(s[i].begin(), s[i].end(), ostream_iterator<int>(cout, " "));    cout << endl;}return make_pair(m, s);}//打印→_→(最优括号化方案)void printOptimalParens(vector<vector<int> > s, int i, int j){if (i == j)   cout << "A" << i;else{cout << "(";printOptimalParens(s, i, s[i][j]);printOptimalParens(s, s[i][j]+1, j);cout << ")";}}const int n = 7;//一般递归方法int recursiveMatrixChain(int (*m)[n], int *p, int i, int j){if (i == j)        return 0;m[i][j] = INT_MAX;for (int k = i; k < j; k++){        int q = recursiveMatrixChain(m, p, i, k) +recursiveMatrixChain(m, p, k+1, j) + p[i-1]*p[k]*p[j];if (q < m[i][j])    m[i][j] = q;}return m[i][j];}//带备忘的自顶向下的递归方法实现int lookUpChain(int (*m)[n], int *p, int i, int j){if (m[i][j] != INT_MAX)    return m[i][j];if (i == j)    m[i][j] = 0;for (int k = i; k < j; k++){int q = lookUpChain(m, p, i, k) +lookUpChain(m, p, k+1, j) + p[i-1]*p[k]*p[j];if (q < m[i][j])    m[i][j] = q;}return m[i][j];}//打印二维数组的右上半部分void displayTwoArray(int (*twoArray)[n]){for (int i = 1; i < 7; i++){for (int j = 1; j < 7; j++){if (j <= i)cout << "  ";elsecout << twoArray[i][j] << " ";}cout << endl;}}int main(){int p[] = {30, 35, 15, 5, 10, 20, 25};vector<int> ivp(p, p+sizeof(p)/sizeof(int));cout << "自底向下的动态规划方法求解: " << endl; printOptimalParens(matrixChainOrder(ivp).second, 1, 6);    cout << endl;cout << "普通递归方法求解:";int m[n][n];cout << recursiveMatrixChain(m, p, 1, 6) << endl;cout << "带备忘的递归方法求解:";cout << lookUpChain(m, p, 1, 6) << endl;system("pause");return 0;}


运行结果为:(我把求出的两个二维数组也打印出来了...)




0 0
原创粉丝点击