挑战密室
时间限制:1000 ms | 内存限制:65535 KB
难度:4
描述
R组织的特工Dr. Kong 为了寻找丢失的超体元素,不幸陷入WTO密室。Dr. Kong必须尽快找到解锁密码逃离,否则几分钟之后,WTO密室即将爆炸。
Dr. Kong发现密室的墙上写了许多化学方程式中。化学方程式,也称为化学反应方程式,是用化学式表示物质化学反应的式子。化学方程式反映的是客观事实。因此书写化学方程式要遵守两个原则:一是必须以客观事实为基础;二是要遵守质量守恒定律。
化学方程式不仅表明了反应物、生成物和反应条件。同时,化学计量数代表了各反应物、生成物物质的量关系,通过相对分子质量或相对原子质量还可以表示各物质之间的质量关系,即各物质之间的质量比。对于气体反应物、生成物,还可以直接通过化学计量数得出体积比。例如:2NaOH+H2SO4=Na2SO4+2H2O
经过多次试探、推理,Dr. Kong发现密码是4位数字,就隐藏在化学方程式等号后的第一个分子中,其分子量就可能是密码(若分子量不足4位,前面加0)。
好在Dr. Kong还记得墙上各化学方程式用到的化学元素的原子量如下:
N | C | O | Cl | S | H | Al | Ca | Zn | Na |
---|---|---|---|---|---|---|---|---|---|
13 | 12 | 16 | 35 | 32 | 2 | 27 | 40 | 65 | 23 |
你能帮Dr. Kong尽快找到密码吗?
输入
第一行: K,表示有K个化学方程式;
接下来有K行,每行为一个化学方程式
输出
对于每个化学方程式输出一行:即密码。
样例输入
3
2C+O2=2CO
2NaOH+H2SO4=Na2SO4+2H2O
Ca2CO3+H2O=Ca2(OH)2+CO2
样例输出
0056
0142
0116
提示
2≤K≤8 ,化学方程式的长度不超过50, 所有原子,分子的数量不超过9.小括号最多一层.
来源
第八届河南省程序设计大赛
今年省赛的题目,当时热身赛里就有类似题目,没做出来,没想到省赛正式赛又出了,ORZ,现在我回头看这道题难度似乎并没有那么大,只是需要考虑的情况多了点,而且重要的是需要打表,昨天静下心来花了三个小时慢慢写最终也是一次AC了,成就感是必须有的啊。
总结了下,本题为了简化思路需要考虑到的几个关键点有:
1、化学式开头可能存在分子数量,放在for循环外处理下,之后就不用考虑数字出现在字母前的情况了(其他数字只可能出现在原子后或者括号后面)
2、每个原子必定是以大写字母开始的,所以遍历字符串的过程中只要遇到大写字母就开始一次分析就OK了。这样就不用考虑下标每次向后移动几位这个让人头疼的问题了、下标一直++就OK了,绝对不会遗漏、因此带来的耗时增加几乎可以忽略不计,测试例子不会太多而且字符串并不长。
3、关于括号问题:之前的想法是一直处理知道碰到括号就把括号里面的字符串提取扔进另外写的一个函数中计算,后来想想其实括号里外的字符处理方式相差其实是不大或者说差不多完全相同的。那么就采用递归,遇到括号就把括号里面的内容递归进去,设置变量接收函数返回值,最终加和到总的结果里,这样就无意中解决了多层括号嵌套的情况(虽然题目中保证并不会出现 - -。)
4、关于打表,建议采用map来做,STL里的东西合理利用起来省好多事情而且通常来说是比较安全的。至少我个人是比较喜欢使用的。
以下是我第一次写的代码:
#include<iostream>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<string.h>
#include<map>
#include<queue>
#include<list>
#include<stack>
#include<cctype>
using namespace std;
map<string, int> M;
int jisuan(string a)
{
map<string, int> M_count;
M_count["N"] = 0;
M_count["C"] = 0;
M_count["O"] = 0;
M_count["Cl"] = 0;
M_count["S"] = 0;
M_count["H"] = 0;
M_count["Al"] = 0;
M_count["Ca"] = 0;
M_count["Zn"] = 0;
M_count["Na"] = 0;
string tmp;
int len = a.length();
for (int i = 0; i < len;)
{
if (isupper(a[i]))
{
if (i + 1 == len)//如果到字符串末尾;
{
tmp = a[i];
M_count[tmp] += 1;
i += 1;
continue;
}
else if (islower(a[i + 1]))//下一位是小写字母;
{