動態規劃解決矩陣連乘問題(C++實現)
阿新 • • 發佈:2019-02-16
1. 採用標準的矩陣乘法來計算M1、M2和M3三個矩陣的乘積M1M2M3,設這三個矩陣的維數分別是2 × 10、10 × 2和2 × 10。如果先把M1和M2相乘,然後把結果和M3相乘,那麼要進行2× 10 × 2 + 2 × 2 × 10 = 80次乘法;如果代之用M2和M3相乘的結果去乘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; }