动态规划之矩阵连乘讲解
注:當時在學矩陣連乘的時候,在網上發現這篇文章總結的不錯,便摘抄了下來,今天與大家共享。同時望原創不要見怪!
動態規劃之矩陣連乘
給定n個矩陣{A1,A2,…,An},其中Ai與Ai+1是可乘的,i=1,2,…,n-1??疾爝@n個矩陣的連乘積A1A2…An。由于矩陣乘法滿足結合律,故計算矩陣的連乘積可以有許多不同的計算次序,這種計算次序可以用加括號的方式來確定。若一個矩陣連乘積的計算次序完全確定,則可以依此次序反復調用2個矩陣相乘的標準算法(有改進的方法,這里不考慮)計算出矩陣連乘積。若A是一個p×q矩陣,B是一個q×r矩陣,則計算其乘積C=AB的標準算法中,需要進行pqr次數乘。
矩陣連乘積的計算次序不同,計算量也不同,舉例如下:
先考察3個矩陣{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。
下面使用動態規劃法找出矩陣連乘積的最優計算次序。
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]。
i=j時為單一矩陣,則m[i][i]=0,
i<j時,設最優計算次序在Ak和Ak+1之間斷開,則m[i][j]=m[i][k]+m[k+1][j]+pipk+1pj+1,其中p表示數組的維數,例如A0到A5共6個數組(為了C語言的描述方便,下標從0開始),他們表示如下:
//p[0]:第一個矩陣的行數
????//p[1]:第一個矩陣的列數,第二個矩陣的行數
????//p[2]:第二個矩陣的列數,第三個矩陣的行數
k此時并未確定,需要從i到j-1遍歷以尋找一個最小的m[i][j]。我們把這個最小的k放在s[i][j]。
?
以下是完整實現代碼,以一個具體的例子實現,稍加修改即可通用。
#include?<iostream>
using?namespace?std;
//
//MatrixChain計算m[i][j]所需的最少數乘次數
//并記錄斷開位置s[i][j]
//
void?MatrixChain(int?*p,int?n,int?**m,int?**s)
{
?????for(int?i=0;i<n;i++)
?????????m[i][i]=0;//單個矩陣相乘,所需數乘次數為0
?
?????//以下兩個循環是關鍵之一,以6個矩陣為例(為描述方便,m[i][j]用ij代替)
?????//需按照如下次序計算
?????//01?12?23?34?45
?????//02?13?24?35
?????//03?14?25
?????//04?15
?????//05
?????//下面行的計算結果將會直接用到上面的結果。例如要計算14,就會用到12,24;或者13,34等等
?????for(int?r=1;r<n;r++)
?????{
?????????for(int?i=0;i<n-r;i++)
?????????{
??????????????int?j=i+r;
??????????????//首先在i斷開,即(Ai*(Ai+1...Aj))
??????????????m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i+1]*p[j+1];
??????????????s[i][j]=i;
??????????????for(int?k=i+1;k<j;k++)
??????????????{
???????????????????//然后在k(從i+1開始遍歷到j-1)斷開,即((Ai...Ak)*(Ak+1...Aj))
???????????????????int?t=m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
???????????????????if(t<m[i][j])//找到更好的斷開方法
???????????????????{
???????????????????????m[i][j]=t;//記錄最少數乘次數
???????????????????????s[i][j]=k;//記錄斷開位置
???????????????????}
??????????????}
?????????}
?????}
?????//如果使用下面注釋的循環,則是按照如下次序計算
?????//01?02?03?04?05
?????//12?13?14?15
?????//23?24?25
?????//34?35
?????//45
?????//當要計算時14,會用到12,24,而此時24并沒有被計算出來。
/*
?????for(int?i=0;i<n;i++)
?????{
?????????for(?int?j=i+1;j<n;j++)
?????????{
??????????????m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i+1]*p[j+1];
??????????????s[i][j]=i;
??????????????for(int?k=i+1;k<j;k++)
??????????????{
???????????????????int?t=m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
???????????????????if(t<m[i][j])
???????????????????{
???????????????????????m[i][j]=t;
???????????????????????s[i][j]=k;
???????????????????}
??????????????}
?????????}
?????}
?????*/
}
//
//Traceback打印A[i:j]的加括號方式
//
void?Traceback(int?i,int?j,int?**s)
{
?????//s[i][j]記錄了斷開的位置,即計算A[i:j]的加括號方式為:
?????//(A[i:s[i][j]])*(A[s[i][j]+1:j])
?????if(i==j)return;
?????Traceback(i,s[i][j],s);//遞歸打印A[i:s[i][j]]的加括號方式
?????Traceback(s[i][j]+1,j,s);//遞歸打印A[s[i][j]+1:j]的加括號方式
?
?????//能走到這里說明i等于s[i][j],s[i][j]+1等于j
?????//也就是說這里其實只剩下兩個矩陣,不必再分了
?????cout<<"A"<<i<<"和A"<<(s[i][j]+1)<<"相乘"<<endl;???
}
?
int?_tmain(int?argc,?_TCHAR*?argv[])
{
?????int?n=6;//矩陣的個數
?????int?*p=new?int[n+1];
?????//p[0]:第一個矩陣的行數
?????//p[1]:第一個矩陣的列數,第二個矩陣的行數
?????//p[2]:第二個矩陣的列數,第三個矩陣的行數
?????p[0]=30;
?????p[1]=35;
?????p[2]=15;
?????p[3]=5;
?????p[4]=10;
?????p[5]=20;
?????p[6]=25;
?
?????int?**m,**s;
?????m=new?int*[n];
?????for(?int?i=0;i<n;i++)
?????????m[i]=new?int[n];
?
?????s=new?int*[n];
?????for(int?i=0;i<n;i++)
?????????s[i]=new?int[n];??
?
?????MatrixChain(p,n,m,s);
?????Traceback(0,n-1,s);
for(int?i=0;i<n;i++)??
?????????{??
??????????????delete?[]m[i];
??????????????m[i]=NULL;
??????????????delete?[]s[i];
??????????????s[i]=NULL;
?????????}??
?????????delete?[]m;??
?????????m=NULL;?
?????????delete?[]s;??
?????????s?=?NULL;
?????????delete?[]p;??
?????????p?=?NULL;?
?????return?0;
}
打印結果是:
A1和A2相乘
A0和A1相乘
A3和A4相乘
A3和A5相乘
A0和A3相乘
實際上要表達的是如下加括號方式:
((A0(A1A2))((A3A4)A5))
加了括號之后用第一個來代替,例如(A1A2)可看作A1,這個結果的數乘次數是15125。
?
具體實例見:
NYOJ 460 項鏈
NYOJ 536 開心的mdd
總結
以上是生活随笔為你收集整理的动态规划之矩阵连乘讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JeecgBoot Minio版本6.0
- 下一篇: NYOJ 417 死神来了