零崎的朋友很多III——矩阵链乘

零崎的朋友很多Ⅲ

时间限制: 1000 ms 内存限制: 65536 kb
总通过人数: 149 总提交人数: 170

题目描述

零崎有很多朋友,其中有一个叫jhljx。

jhljx大家很熟悉了,他数学不好也是出了名的,大家都懂。

现在jhljx遇到了矩阵乘法,他当时就懵了。数都数不清的他,矩阵乘法怎么可能会算的清楚呢?虽然零崎觉得还不如让你们来算,不过好歹也要给jhljx个面子,给她留下一个证明自己数学实力的机会。为了减小jhljx的计算量,让他赶快算出不正确答案来(估计他算上几遍都不一定能出一个正确答案),零崎请你们帮助jhljx。

输入

多组输入数据。

每组数据以N开始,表示矩阵链的长度。接下来一行N+1个数表示矩阵的行/列数。

1<=N<=300

输出

对于每组样例,输出一行最少运算次数的方案,每两个矩阵相乘都用“()”括起来,详见样例

如果存在多种解决方案,最终输出结果选取先计算左边的矩阵,详见Hint

输入样例

3
10 30 5 60
3
10 20 5 4

输出样例

((A1A2)A3)
((A1A2)A3)

Hint

对于输入的第二组数据,

如果计算顺序为((A1A2)A3),结果为10×20×5 + 10×5×4= 1200,

如果计算顺序为A1(A2A3), 结果为20×5×4 + 10×20×4 = 1200

那么输出结果选取第一个


本题分析:

这道题涉及到矩阵链乘的问题。

  首先分析矩阵链乘。在矩阵链乘问题中,实际上并没有把矩阵相乘,目的是确定一个具有最小代价的矩阵相乘顺序。找出这样一个结合顺序使得相乘的代价最低。

那么可以得出状态转移方程:

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

上述方程可以解释为:从第i个矩阵到第j个矩阵的最小代价,等于从第i个矩阵到第k个矩阵的最小代价加上从第k+1个矩阵到第j个矩阵的最小代价,再加上这三个矩阵之间连接的代价。

那么我们就可以在分析的基础上写下代码了。(其实这个代码是参考自某学长的...)

本题的另一个关键点在于输出的问题。这里采用递归的方法,如果i==j,那么就相当于是输出这个矩阵本身;否则的话就需要递归进行加括号处理。

还需要注意的地方是:最终输出的结果选取先计算左边的矩阵。也就是说需要在判断的时候需要m[i][j] >= temp,这里如果不取等于号,我也不知道会出现啥情况,但是感觉上就是因为要找到左边的一个边界值......?嗯对。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define maxn 330

int m[maxn][maxn];//记录从i矩阵到j矩阵的最优值
int rightKey[maxn][maxn];//用来找到正确的划分点
int p[maxn];//用来存储矩阵的行数或者列数
int n;

void printAnswer(int i, int j)
{
    if(i == j)
        printf("A%d", i);
    else 
    {
        printf("(");
        printAnswer(i, rightKey[i][j]);
        printAnswer(rightKey[i][j] + 1, j);
        printf(")");
    }
}

int main(){
    while(scanf("%d", &n) == 1)
    {
        for(int i = 0; i <= n; i++)
        {
            scanf("%d", &p[i]);
        }
        for(int i = 0; i <= n; i++)
            m[i][i] = 0;
        for(int len = 2 ; len <= n; len++)//从第一个矩阵开始,到第n个矩阵结束
        {
            for(int i = 1; i <= n - len + 1; i++)
            {
                int j = i + len - 1;
                m[i][j] = 0x3f3f3f3f;
                for(int k = i; k < j; k++)//找到i和j之间的那一个最优的划分点k
                {
                    int temp = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
                    //cout<<temp<<endl;
                    if(m[i][j] >= temp)
                    {
                        m[i][j] = temp;
                        rightKey[i][j] = k;
                    }

                }
               //cout<<rightKey[i][j]<<endl;
            }
        }

        printAnswer(1, n);
        printf("\n");
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值