励志用尽量少的代码做高效的表达。
题目(提交)链接→UVa-442
储备知识:
矩阵相乘次数:
如图:A矩阵*
B矩阵得到C矩阵。 C矩阵中元素个数=A矩阵行数*B矩阵列数。得到C矩阵中任意元素都需要运算A矩阵的列数次。
因此,总运算次数为:A矩阵行数*
B矩阵列数*
A矩阵列数(B矩阵行数)=2*
2*
3=12次。
同理:求A(BC)的运算次数:
设BC矩阵相乘后得D矩阵。
则总次数=BC相乘后的次数+AD相乘后的次数。
思路:
正常的解析表达式类型题直接用字母运算,但本题每个字母对应不同的矩阵。因此本题实质为解析表达式+字符映射矩阵。采用stack<int>s
存储字母(解析表达式);采用map<char, pair<int, int>>m
分别存储字符、矩阵的行和列(字母映射矩阵)。
实现过程:遍历输入序列,若为字母则压入栈。 若为右括号,则连续弹出两个栈顶元素做运算, 乘法次数累加至sum中。 本次运算完成后, 建立关于map的新字母映射,存入map(map有去重功能,如果不是新字母映射,会自动删去), 同时将新字母压入栈。 继续遍历。
注意:
1、栈弹出的顺序与输入的顺序相反,判断行列相等时不要弄反了。
2、因为输入保证合法,括号无需入栈。
代码:
#include<bits/stdc++.h> //万能头文件
using namespace std;
int main() {
map<char,pair<int, int> >m;
int n; cin >> n; int n1 = n;
while(n--) { //构建map映射
char ch; cin >> ch; //输入字母
cin >> m[ch].first >> m[ch].second; //输入矩阵的行、列数
}
string s; while(cin >> s) { //输入表达式
bool flag = false; //做最后的输出判断。
stack<int>ss;
int len = s.length(), sum = 0; //sum为乘法次数累加
for(int i = 0; i < len; i++) { //遍历表达式
if(isalpha(s[i])) ss.push(s[i]); //如果是字母,则压入栈
else if(s[i] == ')') { //若为右括号,则弹出两个字母做运算
char b = ss.top(); ss.pop();
char a = ss.top(); ss.pop();
if(m[b].first == m[a].second) { //运算过程
sum += m[a].first*m[b].second*m[a].second; //计算乘法次数
m['A'+n1].first = m[a].first; //建立新字母,新映射
m['A'+n1].second = m[b].second;
ss.push((char)('A'+n1++)); //新字母入栈
} else { cout << "error\n"; flag = !flag; break; }
}
}
if(!flag) cout << sum << '\n';
}
return 0;
}
收获:
1、对栈解“解析表达式”更熟练。
2、对map映射运用更加灵活。