[算法导论]矩阵链乘法

#include<stdio.h>
#include<iostream>
#include<limits>

using namespace std;

const int Rows = 3;
const int Columns = 2;
int c[Rows][Rows];

const int N = 6;//矩阵个数
void MatrixMultiply(int a[Rows][Columns], int b[Columns][Rows]);
void MatrixChainOrder(int p[], int n, int m[][N], int s[][N]);
void PrintParens(int s[N][N],int i ,int j);

int main ()
{
    int a[Rows][Columns] = {{1, 2}, {3, 4}, {5, 6}};
    int b[Columns][Rows] = {{1, 2, 3}, {4, 5, 6}};

    MatrixMultiply(a, b);
    for(int i = 0; i < Rows; i++)
    {
        for(int j = 0; j < Rows; j++)
            cout << c[i][j] << "  ";

        cout << endl;
    }

    int p[N + 1]={30,35,15,5,10,20,25};//记录6个矩阵的行和列,注意相邻矩阵的行和列是相同的
	int m[N][N]={0};//存储第i个矩阵到第j个矩阵的计算代价(以乘法次数来表示)
	int s[N][N]={0};//存储第i个矩阵到第j个矩阵的最小代价时的分为两部分的位置
	MatrixChainOrder(p, N, m, s);
	printf("\n最终加括号的形式为: ");
	PrintParens(s, 0, N - 1);//计算从第1个矩阵到第6个矩阵的最优加括号的方法
	printf("\n");
}

void PrintParens(int s[N][N],int i ,int j)
{
	if(i==j)
		printf("A%d",i);
	else
	{
		printf("(");
		PrintParens(s,i,s[i][j]);
		PrintParens(s,s[i][j]+1,j);//递归调用
		printf(")");
	}

}
void MatrixMultiply(int a[Rows][Columns], int b[Columns][Rows])
{
    for(int i = 0; i < Rows; i++)
    {
        for(int j = 0; j < Rows; j++)
        {
            c[i][j] = 0;
            for(int k = 0; k < Columns; k++)
            {
                c[i][j] = c[i][j] + a[i][k] * b[k][j];
            }
        }
    }
}


void MatrixChainOrder(int p[], int L, int m[][N], int s[][N])
{
    int n = L;
    int q = 0, j = 0;
    //m[i, j]表示计算矩阵A(i, j)所需标量乘法次数的最小值
    //则原问题的最优解 计算A(1...n)所需的最小代价就是m[1, n]

    //递归定义m[i,j]如下 对于i=j的平凡问题 矩阵链只包含唯一的矩阵A(i,j)=Ai因此不需要做任何标量乘法运算
    //因此对所有i=1,2,3...n, m[i,i]=0 若i<j则利用最优子结构来计算m[i,j]
    //假设最优括号化方案的分割点在矩阵Ak到Ak+1之间 (i<=k<j)那么 m[i,j]就等于计算A(i...k)和A(k+1...j)的代价加上两者相乘的低价的最小值
    //由于矩阵Ai的大小为pi-1*pi 因此Ai...k与Ak+1...j相乘的代价为
    for(int i = 0; i < n; i++)
    {
        m[i][i] = 0;//0是长度为1的链的最小代价 即Ai...i因此只代表一个矩阵 谈不上最优
                    //因此m的对角线元素值均为0
    }
    for(int l = 2; l <= n; l++)//从计算m[i,i+1](l=2的最小计算代价)开始
    {                           //l=2的执行过程:m[1][2],m[2][3],m[3][4]...
                                //l=3的执行过程:m[1][3],....
        for(int i = 0; i < n - l + 1; i++)
        {
            j = i + l - 1;
            m[i][j] = 100000;//不会出现i=j的情况 因为j=i+l-1 -> 若是i=j则l=1但l是从2开始的
            for(int k = i; k <= j - 1; k++)
            {//q表示当前计算代价 p[i - 1] * p[k] * p[j]代表的是两部分矩阵的乘法代价 对于第i个矩阵来说 它的行数存储在p[i-1]中
                q = m[i][k] + m[k + 1][j] + p[i] * p[k + 1] * p[j + 1];
                if(q < m[i][j])
                {
                    m[i][j] = q;
                    s[i][j] = k;
                }
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值