问题描述
试题编号: | 201912-3 |
---|---|
试题名称: | 化学方程式 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
测试数据
(自己手打的,不知道有没有打错,需要的自己检查一下再用)
11
H2+O2=H2O
2H2+O2=2H2O
H2+Cl2=2NaCl
H2+Cl2=2HCl
CH4+2O2=CO2+2H2O
CaCl2+2AgNO3=Ca(NO3)2+2AgCl
3Ba(OH)2+2H3PO4=6H2O+Ba3(PO4)2
3Ba(OH)2+2H3PO4=Ba3(PO4)2+6H2O
4Zn+10HNO3=4Zn(NO3)2+NH4NO3+3H2O
4Au+8NaCN+2H2O+O2=4Na(Au(CN)2)+4NaOH
Cu+As=Cs+Au
难点及思路
这题的难点在于’(‘和’)'的嵌套问题,可能出现多个嵌套,一般方法都是递归或者用堆栈,这里用了一个“pass”标记,减轻了工作量。我考试的时候用的是递归,然后超时了,最后只有50分。
实现代码
#include<iostream>
#include<string>
#include<sstream>
#include<map>
#include<vector>
using namespace std;
map<string, int> mp[2];
typedef pair<string, int> Elem; // 定义元素,string 存 id , num 存 个数
// 造数: 注意下标要传引用或者指针,保证下标最终指向非数字
int toNumber(string str, int &pos) {
int flag = 0;
while (isdigit(str[pos]))
flag = flag * 10 + str[pos++] - '0';
return flag;
}
void solve(string str, int tag) {
int coe = 1, pos = 0; // coe: 系数, pos: 字符串下标
vector<Elem> arr; // 存元素的数组
if (isdigit(str[pos])) coe = toNumber(str, pos); //算出全局系数,也就是最前面的数字
while (pos < str.size()) {
if (isdigit(str[pos])) { // 遇到数字,就开始计算,除了全局系数,其他系数都存在于元素末尾
int num = toNumber(str, pos);
int i = arr.size() - 1;
if (arr[i].first == ")") { // 数字前一位是')',那么就要一个 '(' , ')' 组合内的所有元素乘倍数
arr[i].first = "pass"; // 并修改标记,表示已经用过,避免嵌套的括号二次利用
while (arr[--i].first != "(") arr[i].second *= num; // 找到对应的'('并修改标记
arr[i].first = "pass";
}
else arr[i].second *= num; // 若数字前不是括号,则为元素本身,那么直接乘倍就好了
}
else if (str[pos] == '(') { //直接入数组
arr.push_back(Elem("(", 0));
pos++;
}
else if (str[pos] == ')') {
arr.push_back(Elem(")", 0));
if (!isdigit(str[++pos])) str.insert(pos, "1"); // 如果')'后面没有数字,那么我们就给他一个‘1’,保证所有都是')'数字结尾
}
else if (isupper(str[pos])) { // 遇到元素
string name = "";
name += str[pos];
pos++;
if (islower(str[pos])) { //若第二位为小写
name += str[pos];
pos++;
}
arr.push_back(Elem(name, 1)); //默认初始值都是 1
}
}
for (int i = 0; i != arr.size(); i++) {
if (arr[i].first == "pass" ) continue; // 遇到非元素直接pass
mp[tag][arr[i].first] += arr[i].second * coe;
}
}
bool Judge(string str) {
mp[0].clear();
mp[1].clear();
int pos = str.find('=');
string tmp;
string left = str.substr(0, pos);
string right = str.substr(pos + 1);
stringstream left_ss(left), right_ss(right);
while (getline(left_ss, tmp, '+')) solve(tmp, 0);
while (getline(right_ss, tmp, '+')) solve(tmp, 1);
if (mp[0].size() != mp[1].size()) return false;
for (map<string, int>::iterator it = mp[0].begin(); it != mp[0].end(); it++)
if (mp[1][it->first] != it->second) return false;
return true;
}
int main() {
int n;
string str;
cin >> n;
while (n--) {
cin >> str;
if (Judge(str)) cout << "Y" << endl;
else cout << "N" << endl;
}
return 0;
}