动态规划_矩阵连乘问题
就会点儿C++,现在看见个问题就想封装封装,我是装运工么!
有关DP的一些列问题,这篇博客写的极好,戳http://www.cnblogs.com/chinazhangjie/archive/2010/11/16/1878400.html
动态规划要素:
1.最优子结构性质:最优解包含着其子问题的最优解.
2.子问题的重叠性质:递归算法求解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次.
3.备忘录方法:为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解。
矩阵连乘问题
(以上是我截图上面链接里的博客内容)
刚开始就这里的P*P*P没明白, 其实就是自己数学sucks!
计算两个矩阵相乘,比如A1*A2,则总共要计算的乘法次数就是30 * 35 *15。那么把A1到A6从k位置分隔开来后,实际还是两个矩阵相乘啦,因为矩阵*矩阵还是矩阵,而且矩阵乘法满足结合律。所以这个P*P*P就是(A1~A6)被分割后,最后还得加上(A1~Ak)和 (Ak+1 ~ A6)这两大矩阵相乘的次数。就好比A1*A2, (i-1)对应30, k对应35, j对应15。
而且实际代码里的两个二维数组m_和 s_都是7*7的矩阵,为的就是不用考虑恼人的下标0的问题。
实际是这样的,外面都多了一圈0.
代码如下(备忘录方法)
1 #ifndef MATRIX_CHAIN_H_
2 #define MATRIX_CHAIN_H_
3 #include <iostream>
4 #include <vector>
5
6 class MatrixChain
7 {
8 public:
9 MatrixChain(int nMatrix, int value[])
10 :nMatrix_(nMatrix), value_(value)
11 {}
12 void initBothMatrix();
13 int lookupChain(int i, int j);
14 void traceChain(int i, int j);
15 void printBest();
16 ~MatrixChain(){}
17
18 private:
19 int* value_; //to store each Matrix's column and the first Matrix'srow
20 int nMatrix_;
21 std::vector<std::vector<int> > m_; //to store min result between 'Matrix_i' and 'Matrix_j'
22 std::vector<std::vector<int> > s_; //to store the segment position, s[i][j]=k
23
24 };
25
26 #endif /*MATRIX_CHAIN_H_*/
1 #include <iostream> 2 #include <vector> 3 #include "MatrixChain.h" 4 using namespace std; 5 6 /* 将两个矩阵m_和s_都初始化为(nMatrix + 1) *(nMatrix + 1)大小的矩阵 7 * 这便于以后的运算,从而无需考虑下标0的问题 8 */ 9 void MatrixChain::initBothMatrix() 10 { 11 m_.resize(nMatrix_ + 1); 12 s_.resize(nMatrix_ + 1); 13 for(int i = 0; i <= nMatrix_; ++i) 14 { 15 m_[i].resize(nMatrix_ + 1); 16 s_[i].resize(nMatrix_ + 1); 17 } 18 19 for(int i = 0; i <= nMatrix_; ++i) 20 { 21 for(int j = 0; j <= nMatrix_; ++j) 22 { 23 m_[i][j] = 0; 24 s_[i][j] = 0; 25 } 26 } 27 } 28 29 30 31 int MatrixChain::lookupChain(int i, int j) 32 { 33 if(m_[i][j] > 0) 34 return m_[i][j]; 35 if(i == j) 36 return 0; 37 int u = lookupChain(i, i) + lookupChain(i + 1, j) + *(value_+i-1) * *(value_+i) * *(value_+j); 38 s_[i][j] = i; 39 40 for(int k = i + 1; k < j; ++k) 41 { 42 int t = lookupChain(i, k) + lookupChain(k + 1, j) + *(value_+i-1) * *(value_+k) * *(value_+j); 43 if(t < u) 44 { 45 u = t; 46 s_[i][j] = k; 47 } 48 } 49 m_[i][j] = u; 50 return u; 51 } 52 53 54 void MatrixChain::traceChain(int i, int j) 55 { 56 if(i == j){ 57 cout << "A"<< i; 58 }else if(i+1 == j){ 59 cout <<"(A" << i << "A" << j << ")"; 60 }else{ 61 cout << "("; 62 traceChain(i, s_[i][j]); 63 traceChain(s_[i][j] + 1, j); 64 cout << ")"; 65 } 66 } 67 68 //for test 69 void MatrixChain::printBest() 70 { 71 /* 72 cout << "m_: " << endl; 73 for(int i = 0; i < nMatrix_; ++i) 74 { 75 for(int j = 0; j<= nMatrix_; ++j) 76 cout << m_[i][j] << " "; 77 cout << endl; 78 } 79 cout << "s_: " << endl; 80 for(int i = 0; i <= nMatrix_; ++i) 81 { 82 for(int j = 0; j<= nMatrix_; ++j) 83 cout << s_[i][j] << " "; 84 cout << endl; 85 } 86 87 */ 88 cout << "min multiply count: " << m_[1][nMatrix_] << endl; 89 }
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #include "MatrixChain.h" 5 using namespace std; 6 7 const int L = 7; 8 //A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*25 9 int main(int argc, const char *argv[]) 10 { 11 //p中记录的是所有矩阵的行与最后一个矩阵的列对应的value 12 int p[L] = {30, 35, 15, 5, 10, 20, 25}; 13 MatrixChain matrix_chain(L-1, p); 14 matrix_chain.initBothMatrix(); 15 matrix_chain.lookupChain(1, L-1); 16 matrix_chain.printBest(); 17 matrix_chain.traceChain(1, L-1); 18 19 return 0; 20 }
Tips:
1.维数组用vector<vector<> >这种方法还真是省心又好用,就是初始化的时候别忘了用.resize()设置下行列的大小,不然会出现越界之类的错误。
2.C++对齐输出两个矩阵:
#include <iomanip>
cout << setw(7) << m_[i][j]; //以宽度7对齐输出