思路分析
每输入一个方程式即处理一个方程式,这样可以减少存储开销。对输入的方程式,将其进行多次切分,首先以“=”为界限,将方程式切分为左半部分和右半部分。此操作在主函数中进行。再对这两部分,以“+”为界限分别进行切割,此时切割出来的称为基本项。此操作在如下函数中进行。

void ProcessExpr(string expr,char side)

对每一个基本项进行处理,首先提取出基本项的系数,比如说4Na(Au(CN)2)的系数是4,Na(OH)2的系数是1,。将系数分离出来之后,得到的就是化学式,上面给出的两个基本项提取系数后得到的化学式分别为Na(Au(CN)2)和NA(OH)2。再遍历化学式的每一个字符,分为如下几种情况。
若当前遍历到的字符是大写字母,则判断下一个字符是否为小写字母,从而得到原子式。之后再提取该原子的下标。
若当前遍历到的字符是’(’,则进入递归处理函数。递归的操作是若遇到’)‘则结束当前函数,若遇到’('则继续进行递归,遇到大写字母则提取其原子式。
本程序的关键就是对括号情况的处理,把括号问题解决之后,其余的就都是一些细节问题了。

#include <iostream>
#include<string>
#include<vector>
#include<stack>
#include<map>
#include<algorithm>
using namespace std;
map<string, int> ma1, ma2;//分别存储方程式的左边和右边的原子
//分离出系数来并存放在coef中
void GetCoef(string formula,int & coef,int & index) {string temp = formula.substr(index);size_t indx = 0;try {coef = stoi(temp, &indx, 10);index += indx;}catch (exception e) { coef = 1; }
}
//处理括号的情况
void ProcessBra(string formula,map<string,int> & bracketMap,int & index) {while (true) {string atom = string(1, formula[index]);index++;if (atom == "(") {map<string, int> inBra;//存放括号里的原子ProcessBra(formula, inBra,index);int num;//括号的下标GetCoef(formula, num, index);for (auto i = inBra.begin(); i != inBra.end(); i++) {//将内层括号中的原子乘以括号的下标之后加到bracketMap中bracketMap[(*i).first] += (*i).second * num;}}else if (atom == ")") {return;}else {if (formula[index] >= 'a' && formula[index] <= 'z') {atom += string(1, formula[index]); index++;}int subscript;//紧跟原子的下标GetCoef(formula, subscript, index);bracketMap[atom] += subscript;}}
}
//处理方程式的每一项
void ProcessFormula(string coefFormula,char side) {int coef = 1;//系数int index = 0;//处理当前项时的索引GetCoef(coefFormula, coef, index);string formula = coefFormula.substr(index);index = 0;map<string, int> tempMap;//存放当前项的原子string atom;while (index < formula.size()) {atom = formula.substr(index, 1);index++;if (atom == "(") {map<string, int> inBra;ProcessBra(formula,inBra, index);int num;//求括号的下标GetCoef(formula, num, index);for (auto i = inBra.begin(); i != inBra.end(); i++) {//将括号中的原子乘以括号的下标之后加到tempMap中tempMap[(*i).first] += (*i).second * num;}}else {if (formula[index] >= 'a' && formula[index] <= 'z') {//判断紧邻的下一个字符是否为小写字母atom += formula[index];index++;}int num;GetCoef(formula, num, index);tempMap[atom] += num;}}for (auto i = tempMap.begin(); i != tempMap.end(); i++) {if(side =='l')//如果是方程式的左侧,则更新ma1,否则更新ma2ma1[(*i).first] += (*i).second *coef;elsema2[(*i).first] += (*i).second *coef;}
}
//将方程式的每一项拆分开
void ProcessExpr(string expr,char side) {int start = 0, end;//充当切分方程时的索引值string coefFormula;//系数和分子式while (true) {end = expr.find('+', start);if (end == -1) {//只剩下最后一项coefFormula = expr.substr(start);ProcessFormula(coefFormula, side);break;}coefFormula = expr.substr(start, end - start);ProcessFormula(coefFormula,side);start = end + 1;}
}
int main()
{int n;string equation;//输入的方程式string left, right;//将方程式以‘=’为界限,分为左半部分和右半部分cin >> n;for (int i = 0; i < n; i++) {ma1.clear(), ma2.clear();cin >> equation;int position = equation.find('=', 0);left = equation.substr(0, position);right = equation.substr(position+1);ProcessExpr(left, 'l');ProcessExpr(right, 'r');if (ma1 != ma2)puts("N");elseputs("Y");}
}

上面给出的源码在CCF系统中经过测试是一百分,但这并不是我最初的代码。刚开始时我是用的结构体存储的原子,对括号的处理也没有采用递归,而是采用了一种栈的思想。比如说化学式Na(Au2(O(CN3)2S)3,在对其每个字符进行遍历时,当遍历到’(’,则把它的位置入栈,遍历到’)’,则弹出栈顶元素,因为没分离出一个原子,就把它顺序的存储到结构体数组中,因此这样就可以定位到括号内的原子。之后再提取括号的下标,让括号内的每个原子的原子数都乘以下标。当时按照这种方法写出的程序却之后90分,找了好长时间也没发现问题在那儿,下面给出源码,还望大神指正。

#include <iostream>
#include<string>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
struct Atom {string name;int amount;
};
Atom atomL[1000],atomR[1000];//方程左侧的原子和右侧的原子
int countL = 0, countR = 0;//方程式左边的元素种类数和右边的元素种类数
void AddToLeft(Atom a) {int i;for ( i = 0; i < countL; i++) {if (a.name == atomL[i].name) {atomL[i].amount += a.amount;break;}}if (i == countL) {atomL[i].name = a.name;atomL[i].amount = a.amount;countL++;}
}
void AddToRight(Atom a) {int i;for (i = 0; i < countR; i++) {if (a.name == atomR[i].name) {atomR[i].amount += a.amount;break;}}if (i == countR) {atomR[i].name = a.name;atomR[i].amount = a.amount;countR++;}
}
//处理方程式的每一项
void ProcessFormula(string coefFormula,char side) {size_t indx = 0;//字符串进行数值转换时,存放转换过程中第一个不被接受的字符的索引int coef = 1;//系数string formula;//分子式try {coef = stoi(coefFormula,&indx,10);}catch (exception e){}formula = coefFormula.substr(indx);vector<Atom> formulaAtom;//当前分子式所含的原子stack<int> bracket;//存放左括号的位置int index = 0;//处理分子式时的索引int count = 0;//记录有多少种原子string atom;while (index < formula.size()) {atom = formula.substr(index, 1);index++;if (atom == "(") {bracket.push(count);}else if (atom == ")") {string temp = formula.substr(index);int num = 1;try {num = stoi(temp, &indx, 10);index += indx;}catch (exception e) {}if (num != 1) {for (int i = bracket.top(); i < count; i++) {formulaAtom[i].amount *= num;}bracket.pop();}}else {string str;str = formula.substr(index, 1);if (str[0] >= 'a'&&str[0] <= 'z') {//判断紧邻的下一个字符是否为小写字母atom += str;index++;}string temp = formula.substr(index);int num = 1;try {num = stoi(temp, &indx, 10);index += indx;}catch (exception e) {}Atom tempAtom = { atom,num };formulaAtom.push_back(tempAtom);count++;}}for (int i = 0; i < count; i++) {formulaAtom[i].amount *= coef;if (side == 'l')AddToLeft(formulaAtom[i]);elseAddToRight(formulaAtom[i]);}
}
//将方程式的每一项拆分开
void ProcessExpr(string expr,char side) {int start = 0, end;//充当切分方程时的索引值string coefFormula;//系数和分子式while (true) {end = expr.find('+', start);if (end == -1) {//只剩下最后一项coefFormula = expr.substr(start);ProcessFormula(coefFormula, side);break;}coefFormula = expr.substr(start, end - start);ProcessFormula(coefFormula,side);start = end + 1;}
}
bool compare(Atom a1, Atom a2) {if (a1.name < a2.name)return true;else return false;
}
//判断方程是否配平
bool Judge() {if (countL == countR) {     sort(atomL, atomL + countL,compare);sort(atomR, atomR + countR,compare);for (int i = 0; i < countL; i++) {if (atomL[i].name != atomR[i].name || atomL[i].amount != atomR[i].amount)return false;}return true;}elsereturn false;
}
int main()
{int n;cin >> n;char result[100];//存放最后的判断结果for (int i = 0; i < n; i++) {countL = countR = 0;string equation;cin >> equation;string left, right;//将方程式以‘=’为界限,分为左半部分和右半部分int position = equation.find('=', 0);left = equation.substr(0, position);right = equation.substr(position+1);ProcessExpr(left, 'l');ProcessExpr(right, 'r');if (Judge())result[i] = 'Y';elseresult[i] = 'N';}for (int i = 0; i < n; i++)cout << result[i] << endl;
}

附测试用例

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

CSP201912-3化学方程式相关推荐

  1. 化学方程式作评、数学上成知识百科……那些“别人家的老师”有何特别?

    懂化学的网友一定知道,上面的两张图是化学方程式,可你知道吗?它不仅是一个方程式,还是一个老师对学生的品评. 近日,浙江金华宾虹中学一位化学老师吕沆菲,给同学用化学方程式作评,并对每个方程式做了解读,和 ...

  2. c语言判断化学方程式,下列是某同学写的六个化学方程式:①Mg+O2点燃.MgO2②C+O2点燃.CO...

    化学方程式是最重要的化学语言,正确.熟练地书写化学方程式是学习化学必需具备的重要基本功. 怎样书写化学方程式? 1.要遵循两个基本原则 (1)以客观事实为基础 化学方程式既然是化学反应的表达形式,显然 ...

  3. 有机物燃烧的化学方程式配平(洛谷P1994题题解,Java语言描述)

    题目要求 P1994题目链接 分析 我太菜了,亏得我高中时期还虐(or被虐)生化,如今多年过去竟然没分析出来坑点,我太菜了. 我开始盲目认为"元素守恒",所以对HHH原子数求和, ...

  4. crout分解计算例题_专题:化学方程式计算

    一. 根据化学方程式的简单计算 (1) 根据化学方程式计算的依据 化学方程式表达的信息之一是反应物与生成物之间在"遵循固定质量比"的前提下的质量守恒.根据这一信息,可以利用化学方程 ...

  5. CCF201912-3 化学方程式(100分)【文本处理】

    试题编号: 201912-3 试题名称: 化学方程式 时间限制: 1.0s 内存限制: 512.0MB 问题链接:CCF201912-3 化学方程式 问题简述:(略) 问题分析:文本处理问题,按字符串 ...

  6. CSP化学方程式题解

    CSP化学方程式题解 题目描述 题目分析 本题主要考察栈的应用(也可以采用递归的方式,效率低),是一道与编译原理相关的题目. 首先我采用的是类似于哈希表的方法存储的元素位置及其数量,当然也可以用stl ...

  7. Python趣用—配平化学方程式

    不知不觉已经毕业多年了,不知道大家是否还记得怎么配平化学方程式呢?反正小编我是已经记不太清了,所以今天的文章除了分享如何用python配平化学方程式,顺带着还会复习一些化学方程式的知识,希望广大化学爱 ...

  8. CCF201912-3 化学方程式*

    参考 https://blog.csdn.net/wingrez/article/details/85111975 https://blog.csdn.net/richenyunqi/article/ ...

  9. PTA Easy chemistry 化学方程式等价判定 string 状态机

    7-5 Easy chemistry In this question, you need to write a simple program to determine if the given ch ...

  10. markdown化学方程式

    之前讲了markdown化学表达式,接下来我来讲讲如何用markdown写化学方程式. $2KMnO_4 \stackrel{\Delta}{=\!=\!=} K_2MnO_4 + MnO_2 + O ...

最新文章

  1. 设计模式之原型模式(Prototype)摘录
  2. 简单介绍实体类或对象序列化时,忽略为空属性的操作
  3. 【windwos bat】批量把windows下的wav文件转为raw文件
  4. Linux数据报文接收发送总结6
  5. 【每周CV论文推荐】 初学深度学习人脸识别和验证必读文章
  6. linux发邮件安装什么意思,linux – 如何找出安装/发送电子邮件的邮件程序?
  7. 解决Linux下MySQL启动错误Starting MySQL.Manager of pid-file quit without updating file.[FAILED]...
  8. PHP函数库之BC高精确度函数库
  9. android弹球动画,Android动画之自定义Evaluator实现弹球效果
  10. CTF之一次曲折获取Flag的过程
  11. Make 输出重定向到文件
  12. 陕西师范大学计算机专业录取,陕西师范大学计算机类专业2016年在湖北理科高考录取最低分数线...
  13. hdu - 1532 Drainage Ditches (最大流)
  14. AutoCAD批量打印工具,batchplot,AcmeCADConverter使用注意事项
  15. 答题卡php,答题卡答题注意事项 - 窗外事 - 简单学习网论坛_中高考学习交流论坛_中学生学习论坛 - Powered by phpwind...
  16. 价值几百元的EMlog仿大表哥资源网模版
  17. 电热毯UL964标准上架亚马逊所需资料流程
  18. win11安卓子系统WSA的安装和使用
  19. 腾讯短网址在线生成(url.cn短网址) 2020最新腾讯短网址生成api接口推荐
  20. 关于C++的数据模型:LP32、ILP32、LLP64、LP64

热门文章

  1. matlab自动运行,自动运行matlab的方法步骤
  2. 利用神经网络预测链家网上海租房价格(Python)
  3. Spring配置数据库密码加密
  4. 老婆学计算机视频,教老婆学电脑-5.14
  5. java使用sapi_JAVA 使用Jacob调用windows的Sapi实现文本转语音文件
  6. 获取手机验证码按钮的效果实现
  7. 视频:忆童年有摇杆,《暗黑破坏神3》街机版演示
  8. 子平真诠释疑笔记(四)
  9. 一段经典模拟退火算法代码
  10. 微信小程序:小程序开发者注册步骤