3. 矩阵连乘问题

(1)   矩阵链连乘问题:

给定n个矩阵{A1,A2,...,An},其中Ai与Ai+1是可乘 的,i=1,2...,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序    计算矩阵连乘积需要的数乘次数最少。

输入数据:共m+1行;第一行为测试数据的组数m;以后每行n+1个正   整数,表示n个矩阵的行列值。

输出:最少次数及连乘的计算次序。

样例输入:

1

5 10 4 6 10 2

样例输出:

348

(A1(A2(A3(A4A5))))

 

思路:

  1.最优子结构:将AiAi+1...Aj 记为 A[ i : j ]。计算 A[ 1 : n ]的最优计算序列,设这个计算次序在矩阵Ak(1<= k <= n)和 Ak+1之间把矩阵连乘断开,其相应的加括号的方式为( ( A1+...+Ak ) ( Ak+1+...+An ) )。它的子链也是最优的(反证法)。

  Count(A[1:n]) = Count(A[1:k])+ Count(A[k+1:n])+ Count(A[1:k] * A[k+1:n])

  2.递推关系式:

  记对于A[ i : j ] 所需的最少乘法次数为m[ i ][ j ]。

  m[ i ][ j ] = 0 (i == j)

  m[ i ][ j ] = min { m[ i ][ k ] + m[ k+1 ][ j ] + pi-1 pk p} (i ≤ k ≤ j,i < j)

  3.计算最优值

  直接递归耗时O(n2),采取记忆化保存结果。

Code:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int INF = 0x3f3f3f3f;
const int maxN = 1000;
vector<int> a;
int m[maxN][maxN];
int s[maxN][maxN];
int n;
struct pos{
    int front;
    int back;
}*p;
void extract (string &s) {
    for (int i = 0; i < s.size(); i++){
        int x = 0;
        while (s[i] != ' ' && i < s.size()){
            x *= 10;
            x += s[i] - '0';
            i++;
        }
        a.push_back(x);
    }
}
void Trace(int i, int j) {
    if (i == j) return;
    Trace(i, s[i][j]);
    Trace(s[i][j]+1, j);
    //cout << "Mutbiply A "<<i<<", "<<s[i][j];
    //cout << "and A "<<(s[i][j]+1)<<", "<<j<<endl;
    p[i].front++;
    p[j].back++;
}
void solve() {
    for (int r = 2; r <= n; r++) {
        for (int i = 1; i <= n-r+1; i++) {
            int j = i+r-1;
            m[i][j] = m[i+1][j] + a[i-1] * a[i] * a[j];
            s[i][j] = i;
            for (int k = i+1; k < j; k++) {
                int t = m[i][k] + m[k+1][j] + a[i-1] * a[k] * a[j];
                if (t < m[i][j]) {
                    m[i][j] = t;
                    s[i][j] = k;
                }
            }
        }
    }
}
int main() {
    int cnt;
    scanf("%d", &cnt);
    getchar();
    while (cnt--) {
        string ss;
        getline(cin, ss);
        memset(m, 0, maxN);
        memset(s, 0, maxN);
        res.clear();
        a.clear();
        extract(ss);
        n = a.size()-1;
        p = new pos[n+1];
        for (int i = 0; i <= n; i++)
            p[i].front = p[i].back = 0;
        solve();
        /*for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++)
                cout << m[i][j]<< ' ';
            cout << endl;
        }*/
        cout << m[1][n] << endl;
        Trace(1,n);
        for (char i = '1'; i <= '0'+n; i++){
            int index = i - '0';
            while(p[index].front --) cout << '(';
            cout << 'A' << i;
            while(p[index].back--) cout << ')'; 
        }
    }
    
    return 0;
} 

 

posted @ 2019-11-02 21:36  莫莫君不恋爱  阅读(710)  评论(0编辑  收藏  举报