算法笔记 //13_矩阵连乘问题

一、问题描述

给定 n 个矩阵:A1,A2,…,An,其中 Ai 与 Ai+1 是可乘的(也就是说Aiy=Ai+1x),i=1,2,…,n-1。确定计算矩阵连乘积的次序,使得依照此次序来计算矩阵连乘积所需要的数乘次数最少(输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数)。
如下例子:
矩阵连乘积 A1A2A3A4 有 5 种不同的完全加括号的方式:(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)。每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定了作乘积所需要的计算量。
详细例子:
计算三个矩阵连乘{A1,A2,A3};维数分别为10*100 , 100*5 , 5*50, 按此顺序计算需要的次数((A1*A2)A3):10X100X5+10X5X50=7500次,按此顺序计算需要的次数(A1(A2*A3)):100*5*50+10*100*50=75000次数乘,是前一种计算方式的10倍。
{矩阵两两相乘求计算量方法为:比如((A1*A2)*A3):A1x*A2x*A2y + A3x*A1x*A2y}

二、C++ 代码

#include<iostream>
using namespace std;

#define MAX 1000

int p[MAX+1];  //p用来记录用户所输入的相邻矩阵的行列值(重复数字只写一遍,所以是 MAX+1)
int m[MAX][MAX];  //m[i][j]用来记录数乘次数最优解
int s[MAX][MAX];  //s[][]用来记录在哪里进行加括号划分

int n; //记录矩阵的个数

void mark() // 标记函数,标记在哪里加括号
{
    for(int i=1; i<=n; i++) m[i][i]=0;  //函数初始化

    for(int r=2; r<=n; r++) //对角线循环
        for(int i=1; i<=n-r+1; i++) //对角线循环格式
        {   
            //行循环
            int j = r+i-1;  //列的控制

            //找m[i][j]的最小值,先初始化一下,令k=i
            m[i][j] = m[i][i] + m[i+1][j] + p[i-1]*p[i]*p[j];
            s[i][j] = i;    // s在这里只是标明加括号的位置

            //k从i+1到j-1循环找m[i][j]的最小值
            for(int k=i+1; k<j; k++)
            {
                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位置处
                    //断开能得到最优解
                    s[i][j]=k;
                }
            }
        }
}

//根据s[][]记录的各个子段的最优解,将其输出
void traceback(int i,int j){ //回溯函数
    if(i==j) return ;

    //同样的递归调用思想
    traceback(i,s[i][j]);
    traceback(s[i][j]+1,j);
    cout << "( A" << i << "," << s[i][j] << " and A" << s[i][j]+1 << "," << j << " )" << endl;
}

void main(){ //主函数

    while(1)
    {
        cout << "Please input the number of matrixs you like: ";     //读取用户输入
        cin >> n;
        cout << "Please input scales of each matrix like\"a1x a2x ... any\": "<< endl;
        for(int i=0; i<=n; i++)
            cin >> p[i];

        mark();

        //输出最好的加括号次序
        cout << "The iearest situation is: " << endl;
        traceback(1,n);

        cout << "And the result is: " << m[1][n] << endl;        //最终解值为m[1][n];
        cout << "-----------------------------------------------------------" << endl;
    }
}

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值