201912-3 CCF CSP认证 化学方程式

题意:给一个化学方程式,验证是否配平。

做法:

         首先我们把等式两边的每一项带系数的化学式都分开,比如H2+O2=2H2O  先拆分成H2 、O2、2H2O

        上边拆好的我们再把系数分离出来,处理单个的化学式比如,2H2O拆分成2  、 H2O 处理H2O

        将刚刚拆出来的H2O,数据信息统计到cnt数组

1. 如果是元素后边直接跟着的数字,我们把这个数字直接给到元素的第一个字母   比如H2CO3 那么 cnt[0] = 2 ,cnt[2]=1,cnt[3] = 3

2. 如果是带括号的,比如(PO4)3那么 我们用一个栈来维护,4我们按上述步骤处理,这个括号外的3要给到“(”对应的位置。

统计好cnt数组后,我们就可以开始统计了,如果碰到的是左括号,那么要乘上相应的cnt,如果碰到的是右括号就要除以相应的cnt

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 1e5+5;
char a[MAXN];
map<string,int>mp1,mp2;
string s;
int cnt[505];
int len;
bool is_litte(char k){
    if(k>='a' && k<='z')return 1;
    else return 0;
}
bool is_big(char k){
    if(k>='A' && k<='Z')return 1;
    else return 0;
}
void jishu(string k){ // 计算cnt数组
    //cout<<k<<endl;
    int sz = k.size();
    stack<int>st;
    int idx=0,nb = 0;
    for(int i=0;i<=sz;i++){
        if(i==sz || is_big(k[i]) ||  k[i] == ')'){
            cnt[idx] = (nb==0)?1:nb;
            //cout<<idx<<" *"<<nb<<endl;
            nb = 0;
            idx = i;
            if(i == sz)break;
            if(i+1<sz && k[i+1]>='a' && k[i+1]<='z'){
                i++;
            }
        }
        if(k[i] == '('){
            st.push(i);
            continue;
        }
        if(k[i] == ')'){
            int kk = st.top();
            st.pop();
            idx = kk;
            cnt[i] = kk;

        }
        if (k[i]>='0' && k[i]<='9'){
            nb = nb*10 +(k[i]-'0');
        }
    }
    for(int i=0;i<sz;i++){
       // cout<<cnt[i]<<" - ";
    }
    //cout<<endl;
}
void hua(string k,bool f){// 分离系数并且计算结果
    memset(cnt,0,sizeof(cnt));
    int xi = 0,idx;
    for(int i=0;i<k.size();i++){
        if(k[i]>='0' && k[i]<='9')
            xi = xi*10 + (k[i]-'0');
        else {
            idx = i;break;
        }
    }
    if(xi == 0)xi = 1;
    string hua2 = k.substr(idx,k.size()-idx);
    jishu(hua2);
    int sz = hua2.size();
    int now = 1;
    string kk = "";
    for(int i=0;i<sz;i++){
        int chu ;
        if(is_big(hua2[i])){
            chu= cnt[i];
            now *= cnt[i];
            kk += hua2[i];
            //cout<<now<<" + ";
            if(i+1 < sz && is_litte(hua2[i+1])){
                i++;
                kk += hua2[i];
            }

            if(!f){
                mp1[kk] += now*xi;
            }
            else mp2[kk] += now*xi;//,cout<<kk<<" -> "<<now*xi<<endl;
            kk = "";
            now /= chu;
        }
        if(hua2[i] == '(')now *= cnt[i];
        if(hua2[i] == ')')now /= cnt[cnt[i]];
    }
   // cout<<endl;
}
bool fun(){ // 提取化学式
    string k = "";
    bool f = 0;
    for(int i=0;i<=len;i++){
        if(i == len || s[i] == '+' || s[i] == '='){
            hua(k,f);
            if(i == len)break;
            if(s[i] == '=')f = 1;
            k = "";
        }
        else k += s[i];
    }
    bool flag = 1;
    for(auto x:mp1){
        string idx = x.first;
        int val = x.second;
       // cout<<idx<<" --> "<<val<<endl;
        if(mp2[idx]!=val)flag = 0;;
    }
    for(auto x:mp2){
        string idx = x.first;
        int val = x.second;
      //  cout<<idx<<" <-- "<<val<<endl;
        if(mp1[idx]!=val)flag = 0;
    }
    return flag;
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        cin>>s;
        len = s.size();
        mp1.clear();
        mp2.clear();
        if(fun()){
            cout<<"Y"<<endl;
        }
        else cout<<"N"<<endl;
    }
}
/*
11
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
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值