一.問題簡述
給定n個矩陣,其中a i 和a i+1 是可乘的,這n個矩陣的連乘積a 1 a 2 …a n 。由於矩陣的乘法滿足結合律,故計算矩陣的連乘積有許多不同的計算次序,而不同的計算次序,所需要計算的連乘次數也是不同的,求解連乘次數最少的矩陣連乘最優次序。
輸入乙個序列p=,矩陣a的維數為pi-1*pi。
假設有三個矩陣a1、a2、a3,三個矩陣的維數分別為10*100,100*5,5*50,則p=
二.演算法分析
按照動態規劃法處理問題的步驟:
(1)最優加括號的全部結構
動態規劃方法的第一步是尋找最優子結構,然後,利用這一子結構,就可以根據子問題的最優解構造出乙個原始問題的最優解。用記號ai..j表示對乘積aiai+1…aj求值的結果;對ai…aj任何加括號的形式都將在ak,與ak+1之間分開。也就是說,對於某個k值,先計算ai..k和ak+1..j然後再把他們相乘,這樣就得到最終乘積ai…j。
(2)乙個遞迴解
對於矩陣鏈乘問題,子問題就是確定aiai+1…aj的加全部括號的最小代價問題,1<=i<=j<=n,m[i,j]為計算矩陣ai..j所需的標量乘法運算的最小值;對於整個問題,計算a1…n的最小代價就是m[1,n]。
(1)矩陣鏈只包含乙個矩陣,即i=j時,m[i,i] = 0;
(2)i < j時,m[i,j]=m[i,k]+m[k+1,j]+pi-1*pk*pj
所以,最優值可以遞迴的定義為:
(3)計算最優代價
使用自底向上的**法來求解最優代價,輸入的是乙個序列p=,表示有n個矩陣相乘a1的維數為p0*p1,a2的維數為p1*p2……以此類推,直到an…,m[1…n,1..n]來儲存m[i,j]的代價,表s[1..n,1..n]來記錄m[i,j]時取得最優代價k的值,即插入括號的位置。
**實現:
#include
#include
#include
#define max 100
/*動態規劃矩陣鏈乘*/
typedef struct
res;
void initp(int* p,int length)
}res matrix_chain_order(int* p,int length)}}
}return
count;
}
我們現在舉例分析假設輸入的序列p=,表示6個矩陣:
矩陣維數
a130*35
a235*15
a315*5
a45*10
a510*20
a620*25
n = length -1;即n=6,為矩陣的個數,中間程式是三層for迴圈巢狀,現在,我們分析程式執行的過程。(l為子問題的規模)
1.◆l=2;l<=n=6;l++(l為子問題的規模),一重for迴圈
●i=1;i<=n-l+1=5;(i為子問題前端點的範圍),二重for迴圈
j=2=i+l-1;(j為子問題後端點的範圍)
m[1,2]=m[i,j]=∞
★ k=i=1;k<=j-1=1;三重for迴圈
q=m[1,1]+m[2,2]+p0*p1*p2=0+0+15750=15750
if (q < count.m[i][j])即15750
m[1,2]=15750;
s[1,2]=k=1;
返回到★處執行k=2時,不滿足for迴圈,返回上一層for迴圈●處,執行i=2,j=3;因此,我們觀察,當子問題規模為l=2時,有以下幾種情況:
子問題規模為2,l=2
m[1,2]=m[1,1]+m[2,2]+p0*p1*p2=0+0+15750=15750 s[1,2]=1
m[2,3]=m[2,2]+m[3,3]=p1*p2*p3=2625 s[2,3]=2
m[3,4]=m[3,3]+m[4,4]=p2*p3*p4=750 s[3,4]=3
m[4,5]=m[4,4]+m[5,5]=p3*p4*p5=1000 s[4,5]=4
m[5,6]=m[5,5]+m[6,6]=p4*p5*p6=5000 s[5,6]=5
2.l=3時,
子問題規模為3,l=3
m[1,3]=min(m[1,1]+m[2,3]+p[0]*p[1]*p[3],m[1,2]+m[3,3]+p[0]*p[2]*p[3]);
m[2,4]=min(m[2,2]+m[3,4]+p[1]*p[2]*p[4],m[2,3]+m[4,4]+p[1]*p[3]*p[4]);
m[3,5]=min(m[3,3]+m[4,5]+p[2]*p[3]*p[5],m[3,4]+m[5,5]+p[2]*p[4]*p[5])
m[4,6]=min(m[4,4]+m[5,6]+p[3]*p[4]*p[6],m[4,5]+m[6,6]+p[3]*p[5]*p[6])
迭代執行該過程,直到l=6為止;
計算過程:
(4)構造最優解
即根據s[1…n,1…n]記錄的資料列印出最優加括號的位置k
void print_optimal_parens(int (*s)[max],int i,int j)
else
}
main函式呼叫的格式:
printf("請輸入下標i,j的值,即輸出最優加全部括號的形式(i,j取值在1~%d之間)\n",length-1);
printf("i=");scanf("%d",&i);
printf("j=");scanf("%d",&j);
printf("%d,a%d,...a%d>最優加全部括號的形式\n",i,i+1,j);
print_optimal_parens(count.s,i,j);
三.總結執行結果:
matrix_chain_order三層巢狀,執行時間為o(n*n*n)
reference:
(1)《演算法導論》15.2矩陣鏈乘法
(2)(3)
矩陣鏈乘 動態規劃
普通矩陣相乘 define row a 2 define col a 2 define col b 3 void matrix mul int mata row a col a int matb 2 col b int c row a col b 兩個相容矩陣相乘,相容是指矩陣a的行必須等於矩陣b的...
動態規劃經典問題 矩陣鏈乘
問題描述 給定n個矩陣,其中ai與ai 1是可乘的,i 1,2,3.n 1.考慮這n個矩陣的乘積。由於矩陣乘法滿足結合律,故計算矩陣的連乘積可以有許多不同的計算機次序。這種計算次序可以用加括號的方式確定。若乙個矩陣鏈乘的計算次序完全確定,這時就說該鏈乘已完全加括號。完全加括號的矩陣鏈乘可遞迴的定義如...
C 動態規劃 矩陣鏈乘
c 動態規劃 矩陣鏈乘 1 問題描述 給定n個矩陣構成的乙個鏈給定 a1,a2,an 其中i 1,2,n.矩陣ai的維數為pi 1 pi,如何確定計算矩陣連乘積的計算次序,使得依此次序計算矩陣連乘積需要的數乘次數最少。2 最優子結構 對乘積a1a2.an的任意加括號方法都會將序列在某個地方分成兩部分...