用c++实现:化学 【问题描述】 SillyHook十分喜欢化学,特别是配平化学方程式。现在Sill...
Creado el: 16 de octubre de 2025
Respondido usando GPT-5 Thinking por Chat01
Creado el: 16 de octubre de 2025
Respondido usando GPT-5 Thinking por Chat01
用c++实现:化学
【问题描述】
SillyHook十分喜欢化学,特别是配平化学方程式。现在SillyHook 有N个化学方程式,请判断它们是否平衡,即元素个数相等。请注意数字 0和字母O的区别。
对于每个化学方程式,按下面的格式描述:
〈公式〉::=[〈数字〉]〈分子式〉{‘+’ [〈数字〉]〈分子式〉}
〈分子式〉::=〈元素〉[〈数字〉]{〈元素〉[〈数字〉]}
〈元素〉::=(化学元素〉| ‘(’〈分子式〉。)’
〈化学元素〉::=〈大写字母〉[〈小写字母〉]
【输入格式】
从文件chem.in中读入数据。
第一行一个化学方程式X。
第二行,一个数字N。
接下来N行,每行一个化学方程式K。
【输出格式】
输出到文件chem.out中。
N行,每行按标号输出X ==匕(X与匕是平衡的)或X!=匕(X 与匕不平衡)。
【样例输入】
C2H5OH+3O2+3(SiO2)
7
2CO2+3H2O+3SiO2
6
绍兴一中noip模拟赛dayl
chem
2C+6H+13O+3Si
99C2H5OH+3SiO2
3SiO4+C2H5OH
C2H5OH+3O2+3(SiO2)+Ge
3(Si(O)2)+2CO+3H2O+O2
2CO+3H2O+3O2+3Si
【样例输出】
C2H5OH+3O2+3(SiO2)==2CO2+3H2O+3SiO2
C2H5OH+3O2+3(SiO2)==2C+6H+13O+3Si
C2H5OH+3O2+3(SiO2)!=99C2H5OH+3SiO2
C2H5OH+3O2+3(SiO2)==3SiO4+C2H5OH
C2H5OH+3O2+3(SiO2)!=C2H5OH+3O2+3(SiO2)+Ge
C2H5OH+3O2+3(SiO2)==3(Si(O)2)+2CO+3H2O+O2
C2H5OH+3O2+3(SiO2)!=2CO+3H2O+3O2+3Si
【数据规模与约定】
30%的数据满足化学方程式中不含括号。
100%的数据满足N < 10,所有的化学方程式长度不大于100 ,每种元 素出现的次数不大于10000 "
下面给你一份健壮的 C++ 实现,按题目给定的文法解析并统计元素计数,判断两个“式子”是否等价(配平)。
支持括号嵌套、项当前系数、省略数字默认 1,并且严格区分数字 0 与字母 O。
说明
- 代码使用
getline
读取第一行 X,再用流读取整数 N,然后再读 N 行式子。- 解析时会忽略空白,输出时使用原始读取的字符串保持题面格式。
- 若你确实要用文件
chem.in/chem.out
,把下面两行freopen
的注释去掉即可。
cpp#include <bits/stdc++.h> using namespace std; struct Parser { string s; // 去空白后的字符串 size_t i = 0; // 当前指针 Parser(const string& raw) { s.reserve(raw.size()); for (char c : raw) { if (!isspace((unsigned char)c)) s.push_back(c); } } bool end() const { return i >= s.size(); } char peek() const { return end() ? '\0' : s[i]; } char get() { return end() ? '\0' : s[i++]; } static bool isUpper(char c){ return c >= 'A' && c <= 'Z'; } static bool isLower(char c){ return c >= 'a' && c <= 'z'; } static bool isDigit(char c){ return c >= '0' && c <= '9'; } // 解析无符号整数;若没有数字则返回 1(题意:省略为 1) long long parseNumberOr1() { if (!isDigit(peek())) return 1; long long v = 0; while (isDigit(peek())) { v = v * 10 + (get() - '0'); } return v; } // 解析元素符号:大写 + 可选的小写(最多一个) string parseElementSymbol() { if (!isUpper(peek())) return {}; string t; t.push_back(get()); if (isLower(peek())) t.push_back(get()); return t; } // 把 src 按系数 mul 加到 dst static void addCounts(map<string,long long>& dst, const map<string,long long>& src, long long mul) { if (mul == 0) return; for (auto &kv : src) dst[kv.first] += kv.second * mul; } // 解析一个“单位”:元素或括号组,返回计数字典(不含外层系数) map<string,long long> parseUnit() { map<string,long long> res; if (peek() == '(') { get(); // '(' auto inside = parseMolecule(); if (peek() == ')') get(); // ')' else { // 合法输入按题面保证;这里可加异常处理 } return inside; } else { string sym = parseElementSymbol(); if (!sym.empty()) res[sym] = 1; return res; } } // 分子式:Element [Number] { Element [Number] } map<string,long long> parseMolecule() { map<string,long long> res; // 至少要有一个单元(元素或 '(') while (!end() && (isUpper(peek()) || peek()=='(')) { auto unit = parseUnit(); long long cnt = parseNumberOr1(); addCounts(res, unit, cnt); } return res; } // 整个“式子”: [Number] Molecule { '+' [Number] Molecule } map<string,long long> parseExpression() { map<string,long long> total; long long coef = parseNumberOr1(); auto mol = parseMolecule(); addCounts(total, mol, coef); while (!end() && peek() == '+') { get(); // '+' long long c = parseNumberOr1(); auto m = parseMolecule(); addCounts(total, m, c); } // 清理 0 项(以防出现 0 系数) for (auto it = total.begin(); it != total.end(); ) { if (it->second == 0) it = total.erase(it); else ++it; } return total; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // 如果需要文件输入输出,取消下一行两行注释 // freopen("chem.in", "r", stdin); // freopen("chem.out", "w", stdout); string X_raw; if (!getline(cin, X_raw)) return 0; int N; if (!(cin >> N)) return 0; string dummy; getline(cin, dummy); // 吃掉行尾换行 // 先解析基准式 X Parser px(X_raw); auto base = px.parseExpression(); for (int i = 0; i < N; ++i) { string K_raw; getline(cin, K_raw); // 若存在空行,继续读到非空(通常评测数据不会这样;仅做稳健处理) while (K_raw.size() == 0 && !cin.fail()) { string t; if (!getline(cin, t)) break; K_raw = t; } Parser pk(K_raw); auto tgt = pk.parseExpression(); bool equal = (base.size() == tgt.size()); if (equal) { for (auto &kv : base) { auto it = tgt.find(kv.first); if (it == tgt.end() || it->second != kv.second) { equal = false; break; } } } if (equal) { cout << X_raw << "==" << K_raw << "\n"; } else { cout << X_raw << "!=" << K_raw << "\n"; } } return 0; }
表达式 -> 分子式 (+ 分子式 …)
,分子式 -> 若干 (元素/括号组) × 可选数字
。map<string,long long>
统计元素到计数的映射;遇到系数就整体乘法累加。0
作为数字,整体贡献为 0(等价于忽略该项)。