用c++实现:化学 【问题描述】 SillyHook十分喜欢化学,特别是配平化学方程式。现在Sill...

创建于:2025年10月16日

使用 GPT-5 Thinking 回答 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 "

思考

Parsing chemical formulas

I need to implement a C++ parser for chemical equations, where we verify if elements and their counts match. The formula follows a specific grammar, but there might be tricky cases with nested parentheses and unwanted noise in the input. I'll need to carefully handle digits, especially distinguishing between 'O' (oxygen) and '0' (zero). The input could have some unusual distractions, like blank lines and irrelevant text, so I'll be cautious when processing.

Handling sample input format

The sample input includes some extraneous lines, such as "6", blank lines, and Chinese text. These seem to be formatting errors or contest-specific info, so I'll ignore them. I'll read the first line as the equation count, the second as the number of formulas, and skip empty lines while reading the formulas. With fewer than 10 formulas and manageable length, this approach should work fine for processing.

Implementing input parsing

First, we'll handle reading the number of equations, ensuring it's correctly parsed, even if there are extra text lines. I'll read each line carefully so it can skip empty ones. For parsing equations like "2CO2+3H2O", we'll compute element counts using a map and compare them for balance in each equation. The extra input cleanup won't hurt, but we expect a clean format from the judge anyway.

Interpreting equations

It looks like the chemical equations aren't left-right reactions but just sums of molecules. So, I'll treat the equation as a composition formula: a sum of molecules with optional coefficients. The goal is to compute element counts for each molecule and compare them across the equations, ensuring counts match. The grammar allows for nested parentheses, so I need to account for that as well when interpreting each molecule.

Parsing and comparing formulas

I need to handle uppercase and lowercase distinctions, making sure to treat 'O' as the element oxygen, not the digit '0'. The challenge involves parsing molecules with optional coefficients, including handling parentheses. I’ll prepare a parser to process each molecule, clean up equations, and compare element counts. After parsing, I'll compare maps, removing zero counts for accuracy. Formatting will preserve original strings while stripping unnecessary spaces. The input will be processed carefully to ignore blank or stray lines.

Thought for 1m 49s

回答

下面给你一份健壮的 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> 统计元素到计数的映射;遇到系数就整体乘法累加。
  • 省略数字按 1 处理;若出现 0 作为数字,整体贡献为 0(等价于忽略该项)。
  • 最终比较两张映射表是否完全一致即可。
  • 复杂度 O(总字符数)。

分享这个问答