UVA-442 Matrix Chain Multiplication

题目:

Matrix Chain Multiplication

Suppose you have to evaluate an expression like A*B*C*D*E where A,B,C,D and E are matrices. Since matrix multiplication is associative, the order in which multiplications are performed is arbitrary. However, the number of elementary multiplications needed strongly depends on the evaluation order you choose.

For example, let A be a 50*10 matrix, B a 10*20 matrix and C a 20*5 matrix. There are two different strategies to compute A*B*C, namely (A*B)*C and A*(B*C).

The first one takes 15000 elementary multiplications, but the second one only 3500.

Your job is to write a program that determines the number of elementary multiplications needed for a given evaluation strategy.

Input Specification

Input consists of two parts: a list of matrices and a list of expressions.

The first line of the input file contains one integer n ( tex2html_wrap_inline28 ), representing the number of matrices in the first part. The next n lines each contain one capital letter, specifying the name of the matrix, and two integers, specifying the number of rows and columns of the matrix.

The second part of the input file strictly adheres to the following syntax (given in EBNF):

SecondPart = Line { Line } Line = Expression Expression = Matrix | “(“ Expression Expression “)” Matrix = “A” | “B” | “C” | … | “X” | “Y” | “Z”

Output Specification

For each expression found in the second part of the input file, print one line containing the word “error” if evaluation of the expression leads to an error due to non-matching matrices. Otherwise print one line containing the number of elementary multiplications needed to evaluate the expression in the way specified by the parentheses.

Sample Input

9 A 50 10 B 10 20 C 20 5 D 30 35 E 35 15 F 15 5 G 5 10 H 10 20 I 20 25 A B C (AA) (AB) (AC) (A(BC)) ((AB)C) (((((DE)F)G)H)I) (D(E(F(G(HI))))) ((D(EF))((GH)I))

Sample Output

0 0 0 error 10000 error 3500 15000 40500 47500 15125

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// oj.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
#include <utility>
#include <stack>
#include <string>

using namespace std;

typedef pair<int, int> P;

int res(P &out, P a, P b)
{
if (a.second != b.first)
return -1;
out.first = a.first;
out.second = b.second;

return a.first*a.second*b.second;
}

P L[30];

int main()
{
ios::sync_with_stdio(false);
cin.tie();
int N;
cin >> N;
while (N--)
{
char name;
cin >> name;
name -= 'A';
cin >> L[name].first >> L[name].second;
}
string expre;
getline(cin, expre);
while (getline(cin, expre))
{
int r = 0;
stack<P> S;
for (int i = 0;i < expre.size();++i)
{
if (expre[i] == '(')
continue;
if (expre[i] == ')')
{
P b = S.top();
S.pop();
P a = S.top();
S.pop();
P c;
int z = res(c, a, b);
if (z == -1)
{
r = -1;
break;
}
r += z;
S.push(c);
continue;
}
S.push(L[expre[i] - 'A']);
}
if (r == -1)
cout << "error" << endl;
else
cout << r << endl;
}
}

解析&吐槽:

一般看起来题目很长的都是水题。注意到底下的算式中每两个需要相乘的矩阵都会放在一个括号中,不会出现(ABC)这样的算式。 因此,每遇到一个右括号就代表要将括号之前的两个矩阵进行矩阵乘法。我们可以使用一个栈来模拟这个过程:

  • 当前的字符是右括号 : 抛弃当前字符
  • 当前的字符是矩阵名称 : 将名称表示的矩阵压栈
  • 当前字符是右括号 : 弹出栈中的前两个矩阵,进行乘法运算,将结果压栈

由此便可以模拟整个表达式的计算过程。我们可以用一个 pair 来表示矩阵的行数和列数,矩阵乘法的过程请参考《线性代数》。在前面的 res 函数中计算 结果,如果遇到了没法相乘的矩阵就输出 error。这个函数可以计算结果矩阵的行数和列数并返回相乘的总次数。我们只需要将结果加起来就可以得到结果了。 另外,如果表达式只有一个矩阵的话,表达式长度必为 1,直接输出结果 0。

本作品采用 署名-相同方式共享 4.0 国际 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 “不科学的科学君” (Liu233w) 与博客链接: https://liu233w.github.io ,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

加载评论框需要翻墙