NYOJ:挑战密室

来源:互联网 发布:400软件 编辑:程序博客网 时间:2024/04/29 08:59

挑战密室

时间限制: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

14

12

16

35

32

2

27

40

65

23

 

你能帮Dr. Kong尽快找到密码吗?

输入
第一行: K,表示有K个化学方程式;
接下来有K行,每行为一个化学方程式
输出
对于每个化学方程式输出一行:即密码。
样例输入
32C+O2=2CO2NaOH+H2SO4=Na2SO4+2H2OCa2CO3+H2O=Ca2(OH)2+CO2
样例输出
005601420116
提示
2≤K≤8 ,化学方程式的长度不超过50, 所有原子,分子的数量不超过9.小括号最多一层.
来源
第八届河南省程序设计大赛

解题思路:题目的意思就是求等号后面第一个化学式的质量。这道题用到数据结构的知识,要用栈来解,坐起来比较麻烦,考虑的情况也是比较多的。这是河南省第八届省赛题,听参加过这届省赛的学长说,这个题目测试数据的的数字都是一位的,因此我的代码是按照一位来考虑的。
首先如果会用sscanf控制输入,可以直接省去等号之前这些字符的输入(可惜我不会),先看等号后面有没有数字,如果有化学计量数,先求出化学计量数,然后用栈来解题。首先所给的元素中O,S,H,他们并不会与其他字母组合产生题目所给出的元素,所以如果遇到字母O,S,H(氧,硫,氢),直接让该元素的相对原子质量进栈。如果我遇到字母N,我要看它的下一位是不是a,如果是a让23进栈,否则14进栈,如果遇到C我要看一下这个元素到底是C(碳),还是Cl(氯),还是Ca(钙),如果下一位是字符'l',那么35进栈,如果下一位是a,那么40进栈,否则12进栈,如果遇到字符'A',证明是Al(铝),27进栈,如果遇到'Z',说明遇到了Zn(锌),如果我到数字字符,就取当前栈顶的元素,并将该元素出栈,乘上这个计量数,然后在入栈,如果我遇到了左括号,我就让-1入栈代表有一个左括号。继续按上述思路处理,如果我遇到了右括号,如果我栈顶元素不是-1,即不是左括号,我就一直让栈顶元素出栈求和,最终求出括号内的这些元素的质量,此时栈顶元素为-1,代表这一对括号处理完毕,然后在看看右括号后面有没有跟数字,如果跟了数字,就要让括号中这些元素的质量和乘上这个计量数在进栈。最终将栈中所有元素的值相加算出一个化学式的质量,如果前面有计量数,我就乘上计量数输出答案,没有计量数,直接输出这个和即可。
正确代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
int main()
{
    int N,i;
    scanf("%d",&N);   //代表有n组测试数据
    getchar();//接收输入N后键入的空格
    char s1[60];
    while(N--)
    {
        int temp1=-1,temp2;//temp1用来存放化学式前面的化学计量数。
        memset(s1,'\0',sizeof(s1));   //刚开始把他刷为‘\0',这样,即使后面的循环访问到len以后的区域也没有关系
        stack<int>s;               //定义一个名为s的栈,栈内元素类型为整型
        gets(s1); //获取化学方程式
        int len=strlen(s1);//测串长
        for(i = 0 ; i < len ; i++)  //如果是’=‘,break;,因为只求等号后面的第一个化学式
            if(s1[i] == '=')
                break;
        if(s1[i+1] >= '0' && s1[i+1] <= '9') //计算化学式前面的化学计量数,
        {
            temp1=s1[i+1]-'0';  i=i+1;
        }
        for(i=i+1 ; i < len ; i++)
        {
            if(s1[i] == '+')  break;//遇到加号说明组成第一个化学式的字符已经全部处理过了
            else
            {
                if(s1[i] == 'O' || s1[i] == 'S' || s1[i] == 'H') //如果是O,S,H,他们不会与其他字符组合产生题目中所给出的搭配
//直接将该元素对应的相对原子质量压栈
                {
                    int a;
                    if(s1[i] == 'O')
                        a=16;
                    if(s1[i] == 'S')
                        a=32;
                    if(s1[i] == 'H')
                        a=2;
                    s.push(a);
                }
                if(s1[i] == 'N') //如果是N
                {
                        if(s1[i+1] == 'a')//下一位是字符'a';
                        {
                            s.push(23);  i++;//23进栈
                        }
                        else  s.push(14);  //否则是N,14进栈
                }
                if(s1[i] == 'C')   //遇到字符C
                {
                        if(s1[i+1] == 'l')//下一位是字符'l'
                        {
                            s.push(35); i++;//是CL,35入栈
                        }
                        else if(s1[i+1] == 'a')//下一位是字符'a'
                        {
                            s.push(40); i++;//是Ca,40进栈
                        }
                        else  s.push(12);  //不是上两种情况,就是C,让12进栈
                }
                if(s1[i] == 'A') //如果是A,说明是Al铝元素,直接让27进栈,i++
                {
                    s.push(27);  i++;
                }
                if(s1[i] == 'Z') //如果是Z,说明是Zn锌元素,直接让65进栈,i++;
                {
                    s.push(65);  i++;
                }
                if(s1[i] >= '0' && s1[i] <= '9')//遇到数字字符
                {
                    temp2=s.top();//取栈顶元素
                    s.pop();//栈顶元素出栈
                    s.push(temp2*(s1[i]-'0'));//乘上计量数之后再入栈
                }
                if(s1[i]=='(')   //如果是左括号,直接让-1进栈,-1只代表是遇到了一对括号
                    s.push(-1);
                if(s1[i]==')')  //如果是右括号,让只要栈顶元素不是-1(不是左括号),就一直让sum1先加栈顶元素,在让栈顶元素出栈,最终sum1为括号内的化学式的质量
                {
                    int sum1=0;//用于括号内元素的质量的累加
                    while(s.top() != -1)//没有遇到左括号,现在栈顶的元素都包含在括号中
                    {
                        sum1 += s.top();
                        s.pop();
                    }
                    s.pop();  //最后把-1出栈,代表这一对括号处理完毕。
                    if(s1[i+1] >= '0' && s1[i+1] <= '9')//然后在考虑右括号后面有没有数字,有的或让数字乘sum1入栈
                    {
                        s.push(sum1*(s1[i+1]-'0')); i=i+1;
                    }
                    else
                        s.push(sum1);  //右括号后面无数字,直接让sum1,入栈
                }
            }
    }
    int sum=0;
    while(!s.empty()) //最终栈中所有数字的和即为等式后第一个化学式的质量
    {
        sum = sum + s.top();
        s.pop();
    }
    if(temp1 != -1)  //如果有化学计量数
        printf("%04d\n",temp1*sum); //一个化学计量数的质量乘上化学计量数
    else
        printf("%04d\n",sum);    //否则,直接输出该化学式的质量即可,%04d是输出整数不足四位自动补0,
    }
    return 0;
}

0 0
原创粉丝点击