1. 程式人生 > >動態規劃--矩陣連乘

動態規劃--矩陣連乘

#include<iostream>

using namespace std;
//無論括號怎麼分這些連續相乘的矩陣,最後括號都可以歸結到只有兩對括號,把整個連乘的矩陣分成兩部分
//          / 0    i==j
//m[i][j] =
//          \ min{ m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j] }  i<j, i<=k<j



//遞迴計算矩陣連乘
int liancheng(int i, int j, int *p, int **s) {
    if (i == j)
        return 0;
    int MIN = liancheng(i, i, p, s) + liancheng(i + 1, j, p, s) + p[i - 1] * p[i] * p[j];
    s[i][j] = i;
    for (int k = i+1; k < j; k++) {
        int rlt = liancheng(i, k, p, s) + liancheng(k+1, j, p, s) + p[i-1]*p[k]*p[j];
        if(rlt < MIN) {
            MIN = rlt;
            s[i][j] = k;
        }
    }
    return MIN;
}

int MatrixChain(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++) { //代表幾個矩陣連乘
        for (int i = 1; i <= n - r + 1; i++) { //i<=n-r+1是怎麼得來的? i+r-1<=n
            int j = i + r - 1;//r個矩陣相乘,最後一個矩陣的座標為j
            m[i][j] = m[i][i] + m[i + 1][j] + p[i - 1]*p[i]*p[j]; //把第一種m[i][j]的值當成是目前最小的,i也就是第一次k的位置
            s[i][j] = i;
            //為了求m[i][j]的所有情況中的最小值
            for (int k = i + 1; k < j; k++) { //因為上面已經計算了k=i的情況,所以繼續往下計算的話,就計算k=i+1,這個地方的k一定是小於j的,不能等於j
                int temp = m[i][k] + m[k + 1][j] + p[i - 1]*p[k]*p[j];
                if (temp < m[i][j]) {
                    m[i][j] = temp;
                    s[i][j] = k;
                }
            }
        }
    }
    return m[1][n];
}

//求最優解,求出加括號的位置
void TraceBack(int i, int j, int **s)
{
    if(i == j) return;
    cout<<"a"<<i<<"~a"<<j<<" 把a"<<i<<"到a"<<s[i][j]<<"括起來, 把a"<<s[i][j]+1<<"到a"<<j<<"括起來"<<endl;
    TraceBack(i, s[i][j], s);
    TraceBack(s[i][j]+1, j, s);
}

//列印s陣列,記錄每個位置加括號的位置
void PrintS(int **s)
{
    for(int i=1; i<=6; i++) {
        for(int j=1; j<=6; j++) {
            cout<<s[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main()
{
    //6個矩陣連乘
    int p[7] = { 30, 35, 15, 5, 10, 20, 25 };//用來存放每個矩陣的行和列數,第一個矩陣的行列為p[0][1], 第二個為p[1][2],第三
                                             //個為p[2][3],依此類推
    int **m; //傳遞二級指標的時候,這樣做,直接int m[][],無法把m當作二級指標引數傳進去
    m = (int **)new int[7];
    for (int i = 0; i < 7; i++) {
        m[i] = (int *)new int[7];
        
    }
    
    int **s;
    s = (int **)new int[7];
    for(int i=0; i<7; i++)
        s[i] = (int *)new int[7];
    
    cout << "遞迴結果: " << liancheng(1, 6, p, s) << endl;
    TraceBack(1, 6, s);
    for(int i=1; i<=6; i++)  //清空s陣列
        for(int j=1; j<=6; j++)
            s[i][j] = 0;
    cout << "動態規劃結果: "<<MatrixChain(p, 6, m, s) << endl;
    TraceBack(1, 6, s);
    return 0;
}