1. 程式人生 > >動態規劃解決矩陣連乘問題(C++實現)

動態規劃解決矩陣連乘問題(C++實現)

1.       採用標準的矩陣乘法來計算M1M2M3三個矩陣的乘積M1M2M3,設這三個矩陣的維數分別是2 × 10、10 × 2和2 × 10。如果先把M1M2相乘,然後把結果和M3相乘,那麼要進行2× 10 × 2 + 2 × 2 × 10 = 80次乘法;如果代之用M2M3相乘的結果去乘M1,那麼數量乘法的次數為10× 2 × 10 + 2 × 10 × 10 = 400。顯然,執行乘法M1(M2M3)耗費的時間是執行乘法(M1M2)M3的5倍。一般來說,n個矩陣M1M2……Mn鏈乘法的耗費,取決於n– 1個乘法執行的順序,請設計一個動態規劃演算法,使得計算矩陣鏈乘法時需要的數量乘法次數達到最小。

矩陣

M1

M2

M3

M4

M5

M6

維數

30 × 35

35 × 15

15 × 5

5 × 10

10 × 20

20 × 25


由於問題中存在大量的重疊子問題,使用分治演算法遞迴得出結果的效率並不高,因此可以使用動態規劃來解決。首先建立一個函式functionD(引數為p陣列:用於存放矩陣的行列數,n:矩陣的規模,二維陣列m用來存放指定範圍矩陣相乘的次數最小值,二維陣列s:用於存放指定範圍矩陣的最佳斷開位置),首先使用for迴圈將單個矩陣相乘的次數設為零,其次通過使用for迴圈來控制矩陣的規模,使其規模遞增,在一個規模裡將預設的斷點設為第一個矩陣處斷開,其次再使用for迴圈控制斷點的移動,然後通過if語句來得出是否為最佳斷點。當所有規模都迴圈結束時,得到的m[i][n]便是整個矩陣鏈的最短乘法次數。

#include <iostream>

using namespace std;


 void functionD(int *p,int n,int **m,int **s) {
	for (int i=1 ; i <= n; i++){
		m[i][i]=0;//將單個矩陣相乘的次數設為0 
	} 
	for(int r=2 ; r <= n; r++) {//r為矩陣鏈的規模 
		for(int i=1; i<=n-r+1;i++){//i為前邊界 
			int j=i+r-1;//j為後邊界 
			m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];//記錄斷點在i處時所需要的乘法次數 
			s[i][j]=i;//將斷點初始化在i處 
			for(int k=i+1;k<j;k++){
				int t=m[i][k]/*實現重疊子問題的利用*/+m[k+1][j]+p[i-1]*p[k]*p[j];
				if(t<m[i][j]) {//如果新的斷點的乘法次數小於原來的次數 
					m[i][j]=t;//更新最少乘法次數 
					s[i][j]=k;//儲存最佳斷點位置 
				}
			} 
		}
	}
}
int main(){
	int p[] = {30,35,15,5,10,20,25};//矩陣鏈的行列數 
	int n=6;//矩陣的個數 
	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];
	}
	 functionD(p,n,m,s) ; 
	cout<<"最少乘法次數為"<<m[1][n]<<endl;
	return 0;
}