算法导论——矩阵链乘法

来源:互联网 发布:做淘宝的心声 编辑:程序博客网 时间:2024/06/18 14:26

【问题描述】
给定有n个连乘矩阵的维数,要求计算其采用最优计算次序时所用的乘法次数,即所要求计算的乘法次数最少。例如,给定三个连乘矩阵{A1,A2,A3}的维数分别是10*100,100*5和5*50,采用(A1A2)A3,乘法次数为10*100*5+10*5*50=7500次,而采用A1(A2A3),乘法次数为100*5*50+10*100*50=75000次乘法,显然,最好的次序是(A1A2)A3,乘法次数为7500次。
分析:
矩阵链乘法问题描述:
给定由n个矩阵构成的序列[A1,A2,...,An],对乘积A1A2...An,找到最小化乘法次数的加括号方法。
1)寻找最优子结构
此问题最难的地方在于找到最优子结构。对乘积A1A2...An的任意加括号方法都会将序列在某个地方分成两部分,也就是最后一次乘法计算的地方,我们将这个位置记为k,也就是说首先计算A1...Ak和Ak+1...An,然后再将这两部分的结果相乘。
最优子结构如下:假设A1A2...An的一个最优加括号把乘积在Ak和Ak+1间分开,则前缀子链A1...Ak的加括号方式必定为A1...Ak的一个最优加括号,后缀子链同理。
一开始并不知道k的确切位置,需要遍历所有位置以保证找到合适的k来分割乘积。
2)构造递归解
设m[i,j]为矩阵链Ai...Aj的最优解的代价,则
              ┌ 0 如果i = j
m[i,j] = │
             └ min(i≤k<j) {m[i,k] + m[k+1,j] + p[i-1] * p[k] *p[j] } 如果i<j
3)构建辅助表,解决重叠子问题
从第二步的递归式可以发现解的过程中会有很多重叠子问题,可以用一个nXn维的辅助表m[n][n] s[n][n]分别表示最优乘积代价及其分割位置k 。
辅助表s[n][n]可以由2种方法构造,一种是自底向上填表构建,该方法要求按照递增的方式逐步填写子问题的解,也就是先计算长度为2的所有矩阵链的解,然后计算长度3的矩阵链,直到长度n;另一种是自顶向下填表的备忘录法,该方法将表的每个元素初始化为某特殊值(本问题中可以将最优乘积代价设置为一极大值),以表示待计算,在递归的过程中逐个填入遇到的子问题的解。

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3. #define N 7  
  4. //p为矩阵链,p[0],p[1]代表第一个矩阵,p[1],p[2]代表第二个矩阵,length为p的长度  
  5. //所以如果有六个矩阵,length=7,m为存储最优结果的二维矩阵,s为存储选择最优结果路线的  
  6. //二维矩阵  
  7. void MatrixChainOrder(int *p,int (*m)[N],int (*s)[N],int length)  
  8. {  
  9.     int n=length-1;  
  10.     int l,i,j,k,q=0;  
  11.     //m[i][i]只有一个矩阵,所以相乘次数为0,即m[i][i]=0;  
  12.     for(i=1;i<length;i++)  
  13.     {  
  14.         m[i][i]=0;  
  15.     }  
  16.     //l表示矩阵链的长度  
  17.     // l=2时,计算 m[i,i+1],i=1,2,...,n-1 (长度l=2的链的最小代价)  
  18.     for(l=2;l<=n;l++)  
  19.     {  
  20.         for(i=1;i<=n-l+1;i++)  
  21.         {  
  22.             j=i+l-1; //以i为起始位置,j为长度为l的链的末位,  
  23.             m[i][j]=0x7fffffff;  
  24.             //k从i到j-1,以k为位置划分  
  25.             for(k=i;k<=j-1;k++)  
  26.             {  
  27.                 q=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];  
  28.                 if(q<m[i][j])  
  29.                 {  
  30.                     m[i][j]=q;  
  31.                     s[i][j]=k;  
  32.                 }  
  33.             }  
  34.         }  
  35.     }  
  36.     cout << m[1][N-1] << endl;  
  37. }  
  38. void PrintAnswer(int(*s)[N],int i,int j)  
  39. {  
  40.     if(i==j)  
  41.     {  
  42.         cout<<"A"<<i;  
  43.     }  
  44.     else  
  45.     {  
  46.         cout<<"(";  
  47.         PrintAnswer(s,i,s[i][j]);  
  48.         PrintAnswer(s,s[i][j]+1,j);  
  49.         cout<<")";  
  50.     }  
  51. }  
  52. int main()  
  53. {  
  54.     int p[N]={20,35,15,5,10,20,25};  
  55.     int m[N][N],s[N][N];  
  56.     MatrixChainOrder(p,m,s,N);  
  57.     PrintAnswer(s,1,N-1);  
  58.     return 0;  
  59. }  
0 0
原创粉丝点击