矩陣鏈乘積

维基百科,自由的百科全书
跳转至: 导航搜索

矩阵链乘积是可用動態規劃解决的最佳化问题。給定一序列矩陣,期望求出相乘這些矩陣的最有效方法。此問題並不是真的去執行其乘法,而只是決定執行乘法的順序而已。

因為矩陣乘法具有結合律,所有其運算順序有很多種選擇。換句話說,不論如何括號其乘積,最後結果都會是一樣的。例如,若有四個矩陣ABCD,將可以有:

(ABC)D = (AB)(CD) = A(BCD) = A(BC)D = ...

但括號其乘積的順序是會影響到需計算乘積所需簡單算術運算的數目,即其效率。例如,設A為一10×30矩陣,B為30×5矩陣與C為5×60矩陣,則

(AB)C 有 (10×30×5) + (10×5×60) = 1500 + 3000 = 4500 個運算
A(BC) 有 (30×5×60) + (10×30×60) = 9000 + 18000 = 27000 個運算

明顯地,第一種方式要有效多了。既然已確認過此問題了,那要如何決定n個矩陣相乘的最佳順序呢?可以比較每一順序的運算量(使用蠻力),但這將需要時間O(2n),是一種非常慢且對大n不實在的方法。那解決方法,如我們將看到的,是將問題分成一套相關的子問題。以解答子問題一次而再使用其解答數次,即可以徹底地得出其所需時間。此一方法稱為動態規劃

算法[编辑]

一開始,假定真的想知道的是乘完矩陣所需的最小成本,或算術運算的最小量。若只有兩個矩陣相乘,則只會有一種方法去乘它們,所有其最小成本為乘積的成本。一般地,可以用下列的遞迴演算法求出最小成本:

  • 取得矩陣的序列且將其分成兩個子序列。
  • 找出乘完每一子序列的最小成本。
  • 將成本加起來,並加上兩個結果矩陣相乘的成本。
  • 在每一矩陣序列可分開的位置運作,並取其最小值。

例如,若有四矩陣ABCD,計算每一分法(A)(BCD)、(AB)(CD)和(ABC)(D)所需的成本,遞迴計算ABCABCDBCD的最小成本。然後選擇最好的一個。這方法不只找出其最小成本,也決定做這乘積的最好辦法:儘只是以最小總成本分開,並對每一因子做相同的事情。

不幸地,若真實作此演算法,將會發現它和比較每一順序的運算量一樣慢!發生什麼事了嗎?答案是因為多做了許多多餘的工作。例如,上述遞迴計算了ABCAB以找到最小成本,但在找出ABC的最小成本時,亦需要去找出AB的最小成本。當遞迴較深時,會有越來越多這種不需要的重複產生。

一簡單的解決方法為備忘錄法:每次計算乘完一特定子序列所需的最小成本時,儲存其數值。若再遇到相同子序列時,便只需讀取已存的答案,而不需要再重計算一次。當n個矩陣會有約n2/2個不同的子序列,其所需空間是合理的。可證明此一簡單的技術可使得運算時間由O(2n)降至O(n3),使得其對實際應用有足夠的效率。此為由上而下動態規劃。

偽代碼:

Matrix-Chain-Order(int p[])
{
    n = p.length - 1;
    for (i = 1; i <= n; i++) 
       m[i,i] = 0;

    for (l=2; l<=n; l++) { // l is chain length
        for (i=1; i<=n-l+1; i++) {
            j = i+l-1;
            m[i,j] = MAXINT;
            for (k=i; k<=j-1; k++) {
                q = m[i,k] + m[k+1,j] + p[i-1]*p[k]*p[j];//Matrix Ai has the dimension  p[i-1] x p[i].
                if (q < m[i,j]) {
                    m[i,j] = q;
                    s[i,j] = k;
                }
            }
        }
    }
}

另一種解決方法是預先知道需要計算的成本並事先計算它們。其運作如下:

  • 對每一由2至矩陣數目nk
    • 計算長度k的子序列的最小成本,使用已計算過的成本。

如此做過之後,將可以得到整個序列的最小成本。即使其亦需要O(n3)的時間,此一方法有其實作的優點,它不需要使用遞迴,不需要測試是否為已計算的值,而且可以丟掉一些已不需要的結果來節省空間。此為由下而上動態規劃:可解答此問題的第二種方法。

此算法在其他领域的用途[编辑]

實作[编辑]

引用[编辑]