矩陣連乘最優結合 動態規划求解


1.引言  多矩陣連乘

對於一般的矩陣乘法來說,如矩陣A(m,n)與矩陣B(n,p)相乘需要進行的加法次數為m*n*p次乘法。

由於矩陣乘法滿足結合律,因此矩陣相乘的結合性,會影響整個計算表達式的乘法執行次數。

如下面的例子,其中A(10,5)、B(5,20)、C(20,3):

    (1) ((AB)C) 執行乘法次數為1300次

    (2) (A(BC)) 執行乘法次數為450次

2.求最優的矩陣結合表達式

(1)設矩陣連乘積AiAi+1…Aj簡記為A[i:j],設最優計算次序在Ak和Ak+1之間斷開,則加括號方式為:

    ((AiAi+1…Ak) (Ak+1…Aj) )

則依照這個次序,先計算A[i:k]和A[k+1:j]然后再將計算結果相乘,計算量是:

    A[i:k]的計算量+A[K+1:j]的計算量+它們兩者相乘的計算量

這里的關鍵是:計算A[i:j]的最優次序所包含的兩個子過程(計算A[i:k]和A[K+1:j])也是最優次序

(2)具體計算

  設計算A[i,j]需要的乘法次數記為m[i,j]。

    M[i,j] = 0;    (i == j,表示一個矩陣,當然不需要乘法運算)

    M[i,j] = min(M[i,k]+M[k+1,j]+pi*pk*pj);   (k在[i,j)之間取值,表示分割點的位置,求最適合的分割點使得乘法次數最少)

  下面是使用動態規划計算6個矩陣連乘的示意圖。可以使用自底向上計算,這樣矩陣的分割點好計算。如先計算01兩個矩陣乘積,在計算02三個矩陣乘積,在計算03四個矩陣乘積:

       01 12 23 34 45

       02 13 24 35

       03 14 25

       04 15

       05

 3.程序實例

程序可以根據給出的多個矩陣的行、列,生成最優結合的相乘表達式。

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <limits.h>
 5 #include <string>
 6 using namespace std;
 7 ///計算M矩陣
 8 int calculate_M(vector<vector<int> >&num,vector<pair<int,int> > &data,vector<vector<int> > &points){
 9     int len = data.size();
10     for(int span = 1;span<len;span++){  ///間隔距離
11         for(int col=0;col<len-span;col++){  ///操作起始列
12 
13             for(int i=col;i<col+span;i++){
14                 int tmp = num[col][i] + num[i+1][col+span] + data[col].first*data[i].second*data[col+span].second;
15                 if(tmp < num[col][col+span]){
16                     points[col][col+span] = i;  ///記錄分割點
17                     num[col][col+span] = tmp;   ///記錄最少乘法次數
18                 }
19             }
20         }
21     }
22     return 0;
23 }
24 
25 ///根據記錄的分割點,生成最后的矩陣相乘表達式
26 string make_result(vector<vector<int> > &points,int t1,int t2){
27     if(t1 == t2)
28         return string(1,'A'+t1);
29     int split = points[t1][t2];
30     return "("+make_result(points,t1,split)+"*"+make_result(points,split+1,t2)+")";
31 }
32 
33 int main()
34 {
35     vector<pair<int,int>> data; ///保存矩陣的行、列
36     data.push_back(make_pair(10,100));  //A
37     data.push_back(make_pair(100,5));   //B
38     data.push_back(make_pair(5,25));    //C
39     data.push_back(make_pair(25,15));   //D
40     data.push_back(make_pair(15,20));   //E
41 
42 
43     int len = data.size();
44     vector<vector<int> > num(len,vector<int>(len)); ///定義二維向量,並預先分配空間,記錄乘法次數
45     vector<vector<int> > points(len,vector<int>(len)); ///定義二維向量,並預先分配空間,記錄分割點
46     for(int i=0;i<len;i++){
47         for(int j=0;j<len;j++){
48             points[i][j] = -1;
49             if(i == j)
50                 num[i][j] = 0;  ///自己和自己相乘,所以為0
51             else
52                 num[i][j] = INT_MAX;    ///否則,記為最大整數值
53         }
54     }
55 
56     calculate_M(num,data,points);
57     cout<<make_result(points,0,len-1)<<"\t最少乘法次數為:"<<num[0][len-1]<<endl;
58     return 0;
59 }
View Code

輸入矩陣,表示每個矩陣的行、列:

輸出最優的結合表達式:

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM