zoukankan      html  css  js  c++  java
  • 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;
    } 
  • 相关阅读:
    关于链表的代码
    c++中的友元函数
    javaweb笔记全套
    包装类、object、单例模式、final、抽象类
    Linux变量内容的删除、代替与替换
    2014年工作中遇到的20个问题:181-200
    Qt中 QString 和int,double等的转换
    jsp学习笔记总结
    工作日志2014-07-04
    Maple入门使用教程
  • 原文地址:https://www.cnblogs.com/astonc/p/11784286.html
Copyright © 2011-2022 走看看