矩阵链乘 Matrix Chain Multiplication
题目描述
假设你必须评估一种表达形如 ABCDE,其中 A,B,C,D,E是矩阵。既然矩阵乘法是关联的,那么乘法的顺序是任意的。然而,链乘的元素数量必须由你选择的赋值顺序决定。
例如,A,B,C分别是 50 * 10 ,10 * 20 和 20 * 5 的矩阵。现在有两种方案计算 A * B * C ,即(A * B) * C 和 A*(B * C)。
第一个要进行15000次基本乘法,而第二个只进行3500次。
你的任务就是写出一个程序判定以给定的方式相乘需要多少次基本乘法计算。
输入格式
输入包含两个部分:矩阵和表达式。
输入文件的第一行包含了一个整数 n(1
≤
\leq
≤ n
≤
\leq
≤ 26), 代表矩阵的个数。接下来的n行每一行都包含了一个大写字母,说明矩阵的名称,以及两个整数,说明行与列的个数。
第二个部分严格遵守以下的语法:
SecondPart = Line { Line }
Line = Expression
Expression = Matrix | “(” Expression Expression “)”
Matrix = “A” | “B” | “C” | … | “X” | “Y” | “Z”
输出格式
对于每一个表达式,如果乘法无法进行就输出 " error "。否则就输出一行包含计算所需的乘法次数。
样例 #1
样例输入 #1
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))
样例输出 #1
0
0
0
error
10000
error
3500
15000
40500
47500
15125
题目分析
这道题考察 栈 这种数据结构,类似于表达式求值.
另外分析题目可知,矩阵相乘需要两两配对,不同的求值顺序,其乘法次数不一定相同,所以题目给出的输入有一个特点,就是任意一对括号内必有一对矩阵
解题思路:
这里的矩阵表示可以使用c++提供的二元组pair,或者自定义
这里自定义一个数据结构Matrix包含矩阵的行和列.
使用map来记录符号和对应的矩阵.
使用stack来进行算法设计.
#include <iostream>
#include <stack>
#include <map>
#include <string>
using namespace std;
typedef struct Matrix{
int rows;
int cols;
Matrix(){
}
Matrix(int rows, int cols):rows(rows), cols(cols){
}
}Matrix;
map<string, Matrix> vars;
int compute(string& expression);
int main(int argc, char **argv){
int n = 0;
cin >> n;
for(int i = 0; i < n; i++){
string name;
int rows;
int cols;
cin >> name >> rows >> cols;
vars[name] = Matrix(rows, cols);
}
string expression;
while(cin >> expression){
int result = compute(expression);
if(result == -1){
cout << "error" << endl;
}else{
cout << result << endl;
}
}
return 0;
}
int compute(string& expression){
stack<string> symbols;
int result = 0;
int length = expression.length();
if(length == 1){
return result;
}
for(int i = 0; i < length; i++){
string tmp = string(1, expression[i]);
if(tmp == "("){
symbols.push(tmp);
}else if(tmp == ")"){
string m[2];
for(int j = 0; j < 2; j++){
m[j] = symbols.top();
symbols.pop();
}
symbols.pop();
if(vars[m[1]].cols != vars[m[0]].rows){
return -1;
}
Matrix right = vars[m[0]];
Matrix left = vars[m[1]];
result += left.rows * left.cols * right.cols;
if(!symbols.empty()){
Matrix mat = Matrix(left.rows, right.cols);
string name = m[1]+m[0];
vars[name] = mat;
symbols.push(name);
}else{
return result;
}
}else{
symbols.push(tmp);
}
}
}