P4711【化学】 相对分子质量 简单题解

· · 题解

本蒟蒻写的第一道大模拟题(我们机房某巨佬说是中模拟

我:“ A了这道题,妈妈再也不同担心我算不对相对分子质量啦~ ”

思路

做这种模拟题时,需要一个明确的思路。

我们在开始之前,先来研究一下这些化学式。

这些化学式,由小括号,大括号,下划线,数字,化学元素组成。

看到这些,是不是觉得无从下手?是不是尝试去实现了但是实现不了?

别着急,慢慢来。

我们先讨论单个的元素。eg: Ag , Cu

对于单个的元素,我们只需要预先将这些元素与他们的相对原子质量存好,用的时候调出来就可以了。对于这个,我们可以用一个map实现(STL大法好)。

更具体的,map应该这样定义:map<string,double> (具体的待会可以看看代码)

好,单个元素讲完了,现在我们来讨论没有原子团且有一个元素有下标的化学物质。 eg: CO_2 Na_2SO_4

首先,我们需要一个 i 游标来确定现在正在读的字符位置, last 来记录上一个元素的相对原子质量。

接下来,如果检测到元素,并且该元素的下一位不是下划线,答案加上该元素的相对原子质量。否则启动 last 记录当前读入元素的相对原子质量。

有下标的化学元素解决啦,下面开始讨论带有原子团的化学式。

哎,带有小括号的喔,怎么玩啊?(之前就是在这里卡了半天

别慌,我们来试着把整个化学式括起来。

这个时候我们可以很容易的发现,对于带括号的,我们只需要单独解决括号里面的内容就行了。怎么解决?当然是递归啦~。因为括号里面的内容都还是原子团或者化学式。

最后剩下的是带水的化学式,我们单独处理它。首先读入的时候寻找水分子连接符 “~” ,再将它后面的数字读入就可以了,如果没有数字,默认为 1 。

友情提示:建议除了游标使用整型变量,其他的运算都要用 double 类型。

代码

接下来是大家最喜欢的代码~

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<map>
#define ll long long
using namespace std;

map<string,double> app;

double ans;

string elememts[26]={"H","C","N","O","F","Na","Mg","Al","Si","P","S","Cl","K","Ca","Mn","Fe","Cu","Zn","Ag","I","Ba","Hf","Pt","Au","Hg"};
string s;

void init_elements()
{
    for(int i=0;i<25;++i)  //这样有点小麻烦了
    {
        if(i==0) app[elememts[i]]=1;
        if(i==1) app[elememts[i]]=12;
        if(i==2) app[elememts[i]]=14;
        if(i==3) app[elememts[i]]=16;
        if(i==4) app[elememts[i]]=19;
        if(i==5) app[elememts[i]]=23;
        if(i==6) app[elememts[i]]=24;
        if(i==7) app[elememts[i]]=27;
        if(i==8) app[elememts[i]]=28;
        if(i==9) app[elememts[i]]=31;
        if(i==10) app[elememts[i]]=32;
        if(i==11) app[elememts[i]]=35.5;
        if(i==12) app[elememts[i]]=39;
        if(i==13) app[elememts[i]]=40;
        if(i==14) app[elememts[i]]=55;
        if(i==15) app[elememts[i]]=56;
        if(i==16) app[elememts[i]]=64;
        if(i==17) app[elememts[i]]=65;
        if(i==18) app[elememts[i]]=108;
        if(i==19) app[elememts[i]]=127;
        if(i==20) app[elememts[i]]=137;
        if(i==21) app[elememts[i]]=178.5;
        if(i==22) app[elememts[i]]=195;
        if(i==23) app[elememts[i]]=197;
        if(i==24) app[elememts[i]]=201;
    }
}

double water(int l,int r)
{
    int i=l+1,num=0;
    while(s[i]>='0'&&s[i]<='9')
    {
        num=num*10+s[i]-'0';
        i++;
    }
    if(num==0) return 18;
    return num*18;
}

double answer(int l,int r)
{
    int i=l;
    double now=0,last=0;
    while(i<=r)
    {
        if(s[i]>='A'&&s[i]<='Z')
        {
            if(s[i+1]>='a'&&s[i+1]<='z') 
            {
                if(s[i+2]!='_')
                {
                    string str;
                    str+=s[i];
                    str+=s[i+1];
                    now+=app[str];
                    i+=2;
                }
                else 
                {
                    string str;
                    str+=s[i];
                    str+=s[i+1];
                    now+=app[str];
                    last=app[str];
                    i+=2;
                }
            }
            else 
            {
                if(s[i+1]!='_')
                {
                    string str;
                    str=s[i];
                    now+=app[str];
                    i++;
                }
                else
                {
                    string str;
                    str=s[i];
                    now+=app[str];
                    last=app[str];
                    i++;
                }   
            }
        }
        if(s[i]=='(')
        {
            int j;
            for(j=i+1;j<s.size();++j)
            {
                if(s[j]==')') break;
            }
            double t=answer(i+1,j-1);
            i=j+1;
            if(s[i]=='_') 
            {
                last=t;
            }
            now+=t; 
        }
        if(s[i]=='_')
        {
            if(last==0)
            {
                string str2;
                str2=s[i-1];
                i+=2; 
                int num=0;
                while(s[i]!='}')
                {
                    num=num*10+s[i]-'0';
                    i++;
                }
                now+=(num-1)*app[str2]; 
            }
            else
            {
                int num=0;
                i+=2;
                //cout<<s[i]<<" ";
                while(s[i]!='}')
                {
                    num=num*10+s[i]-'0';
                    i++;
                }
                now+=(num-1)*last;
            }       
            i++;    
        }
        if(s[i]=='~') return now; 
    }
    return now;
}

int main()
{
    init_elements();  //化学元素初始化
    cin>>s;
    ans=answer(0,s.size()-1);  
    int t=s.find('~',0);
    if(t!=s.npos) ans+=water(t,s.size()-1);
    cout<<ans<<endl;
    return 0;
}