算法13---動態規划矩陣鏈乘法


算法13---動態規划矩陣鏈乘法

矩陣鏈乘法是動態規划里面使用到的一個例子
 
1 兩個矩陣的計算
 
那么對於一個矩陣的乘法,首先如果是兩個矩陣的乘法,那么如何實現呢?
注意到我們使用二維數組表示矩陣,但是二維數組不能作為函數的返回值。具體實現如下
 
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <math.h>
 4 
 5 #define a_rows  3
 6 #define a_columns 4
 7 #define b_rows  4
 8 #define b_columns 3
 9 
10 void matrix_multiply(int a[a_rows][a_columns],int b[b_rows][b_columns],int c[a_rows][b_columns])
11 {
12     if (a_columns!=b_rows)
13     {
14         printf("error!can't figure the answer!\n");
15     }
16     for (int i = 0; i < a_rows; i++)
17     {
18         for (int j = 0; j < b_columns; j++)
19         {
20             c[i][j]=0;
21             for (int k = 0; k< a_columns; k++)
22             {
23                 c[i][j]=c[i][j]+a[i][k]*b[k][j];
24             }
25         }
26     }
27 }
28 
29 int main()
30 {
31 
32     printf("it is a easy matrix \n");
33 
34     int a[a_rows][a_columns]={{1,1,1,1},{2,2,2,2},{3,3,3,3}};
35     int b[b_rows][b_columns]={{1,1,1},{2,2,2},{3,3,3},{4,4,4}};
36     int c[a_rows][b_columns]={0};
37     matrix_multiply(a,b,c);
38     for (int i = 0; i < 3; i++)
39     {
40         for (int j = 0; j < 3; j++)
41         {
42             printf("%d  \n",c[i][j]);
43             if (j==2)
44             {
45                 printf("\n");
46             }
47         }
48     }
49     return 0;
50 }

 

2 矩陣鏈問題
 
問題描述
     給定n個矩陣構成的一個鏈<A 1,A 2,A 3,.......A n>,其中i=1,2,...n,矩陣A的維數為p i-1p i,對乘積 A 1A 2...A 以一種最小化標量乘法次數的方式進行加全部括號。
  換句話說,就是在矩陣鏈乘問題中,實際上並沒有把矩陣相乘,目的是確定一個具有最小代價的矩陣相乘順序。找出這樣一個結合順序使得相乘的代價最低。
 
一般的過程如下
(1)最優括號話方案的結構特征
  假設AiAi+1....Aj的一個最優加全括號把乘積在Ak和Ak+1之間分開,則Ai..k和Ak+1..j也都是最優加全括號的。
 
(2)一個遞歸求解方案
     設m[i,j]為計算機矩陣Ai...j所需的標量乘法運算次數的最小值,對此計算A1..n的最小代價就是m[1,n]。現在需要來遞歸定義m[i,j],分兩種情況進行討論如下:
 
     當i==j時:m[i,j] = 0,(此時只包含一個矩陣)
     當i<j 時:從步驟1中需要尋找一個k(i≤k<j)值,使得m[i,j] =min{m[i,k]+m[k+1,j]+pi-1pkpj} (i≤k<j)。
 
(3)計算最優代價
我們不采用遞歸實現,而是自下向上的借助輔助空間保存中間量實現;
 
(4)構造一個最優解
 
 
具體的實現過程如下面所示
 
還沒有調好,主要是二維數組不能作為返回值

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define N 6
  5 #define MAXVALUE 999999
  6 
  7 void recursive_matrix_chain(int *p,int i,int j,int m[N+1][N+1],int s[N+1][N+1]);
  8 int memoized_matrix_chain(int *p,int m[N+1][N+1],int s[N+1][N+1]);
  9 int lookup_chain(int *p,int i,int j,int m[N+1][N+1],int s[N+1][N+1]);
 10 
 11 //我們首先采用遞歸來實現
 12 void recursive_matrix_chain(int *p,int i,int j,int m[N+1][N+1],int s[N+1][N+1])
 13 {
 14     if (i==j)
 15     {
 16         m[i][j]=0;
 17     }
 18     else
 19     {
 20         int k;
 21         m[i][j]=MAXVALUE;
 22         for (int k = i; k < j; k++)
 23         {
 24             int temp=recursive_matrix_chain(p,i,k,m,s)+recursive_matrix_chain(p,k+1,j,m,s)+p[i-1]*p[k]*p[j];
 25             if (temp<m[i][j])
 26             {
 27                 m[i][j]=temp;
 28                 s[i][j]=k;
 29             }
 30         }
 31 
 32     }
 33 }
 34 
 35 //因為遞歸的計算量太大,所以我們可以采用備忘錄的方法,自頂向下實現
 36 
 37 int memoized_matrix_chain(int *p,int m[N+1][N+1],int s[N+1][N+1])
 38 {
 39 
 40     for (int i = 1; i <=N; ++i)
 41     {
 42         for (int j = 0; j <=N; ++j)
 43         {
 44             m[i][j]=MAXVALUE;
 45         }
 46     }
 47     return lookup_chain(p,1,N,m,s);
 48 }
 49 
 50 int lookup_chain(int *p,int i,int j,int m[N+1][N+1],int s[N+1][N+1])
 51 {
 52     if (m[i][j]<MAXVALUE)
 53     {
 54         return m[i][j];
 55     }
 56     if (i==j)
 57     {
 58         m[i][j]=0;
 59     }
 60     else
 61     {
 62         for (int k = i; i < j; ++k)
 63         {
 64             int temp=lookup_chain(p,i,k,m,s)+lookup_chain(p,k+1,j,m,s)+p[i-1]*p[k]*p[j];
 65             if (temp<m[i][j])
 66             {
 67                 s[i][j]=k;
 68             }
 69         }
 70     }
 71     return m[i][j];
 72 }
 73 
 74 
 75 void print_optimal_parens(int s[N+1][N+1],int i,int j)
 76 {
 77     if (i==j)
 78     {
 79         printf("A%d\n",i);
 80     }
 81     else
 82     {
 83         printf("(");
 84         print_optimal_parens(s,i,s[i][j]);
 85         print_optimal_parens(s,s[i][j]+1,j);
 86         printf(")");
 87     }
 88 }
 89 
 90 int main()
 91 {
 92     int p[N+1] = {30,35,15,5,10,20,25};
 93     int m[N+1][N+1]={0};
 94     int s[N+1][N+1]={0};
 95     int i,j;
 96     memoized_matrix_chain(p,N+1,m,s);
 97     printf("m value is: " );
 98 
 99     for(i=1;i<=N;++i)
100     {
101         for(j=1;j<=N;++j)
102             printf("%d ",m[i][j]);
103         printf("\n");
104     printf("s value is: \n");
105 
106     for(i=1;i<=N;++i)
107     {
108         for(j=1;j<=N;++j)
109             printf("%d ",s[i][j]);
110         printf("\n");
111     }
112     printf("the result is:\n");
113     print_optimal_parents(s,1,N);
114     return 0;
115 }

 

 

現在再給出一個c++的版本,一個實現,我是看的別人的,自己可以修改

 

 1 #include <iostream>
 2 using namespace std;
 3 
 4 #define N 6
 5 #define MAXVALUE 1000000
 6 
 7 void matrix_chain_order(int *p,int len,int m[N+1][N+1],int s[N+1][N+1]);
 8 void print_optimal_parents(int s[N+1][N+1],int i,int j);
 9 
10 int main()
11 {
12     int p[N+1] = {30,35,15,5,10,20,25};
13     int m[N+1][N+1]={0};
14     int s[N+1][N+1]={0};
15     int i,j;
16     matrix_chain_order(p,N+1,m,s);
17     cout<<"m value is: "<<endl;
18     for(i=1;i<=N;++i)
19     {
20         for(j=1;j<=N;++j)
21             cout<<m[i][j]<<" ";
22         cout<<endl;
23     }
24     cout<<"s value is: "<<endl;
25     for(i=1;i<=N;++i)
26     {
27         for(j=1;j<=N;++j)
28             cout<<s[i][j]<<" ";
29         cout<<endl;
30     }
31     cout<<"The result is:"<<endl;
32     print_optimal_parents(s,1,N);
33     return 0;
34 }
35 
36 void matrix_chain_order(int *p,int len,int m[N+1][N+1],int s[N+1][N+1])
37 {
38     int i,j,k,t;
39     for(i=0;i<=N;++i)
40         m[i][i] = 0;
41     for(t=2;t<=N;t++)  //當前鏈乘矩陣的長度
42     {
43         for(i=1;i<=N-t+1;i++)  //從第一矩陣開始算起,計算長度為t的最少代價
44         {
45             j=i+t-1;//長度為t時候的最后一個元素
46             m[i][j] = MAXVALUE;  //初始化為最大代價
47             for(k=i;k<=j-1;k++)   //尋找最優的k值,使得分成兩部分k在i與j-1之間
48             {
49                 int temp = m[i][k]+m[k+1][j] + p[i-1]*p[k]*p[j];
50                 if(temp < m[i][j])
51                 {
52                     m[i][j] = temp;   //記錄下當前的最小代價
53                     s[i][j] = k;      //記錄當前的括號位置,即矩陣的編號
54                 }
55             }
56         }
57     }
58 }
59 
60 //s中存放着括號當前的位置
61 void print_optimal_parents(int s[N+1][N+1],int i,int j)
62 {
63     if( i == j)
64         cout<<"A"<<i;
65     else
66     {
67         cout<<"(";
68         print_optimal_parents(s,i,s[i][j]);
69         print_optimal_parents(s,s[i][j]+1,j);
70         cout<<")";
71     }
72 
73 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM