CCF 2019-12 第三题 化学方程式配平

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题解:

字符串模拟
  题目意思很明确就是判断化学方程式是否配平。
基本思路:就是对化学方程式左边和右边的元素进行计数,然后判断所有的元素的数量是否相等即可。
  第一步:对字符串进行拆分
     1、以 ‘=’ 进行拆分,将字符串分为左右两个串
     2、分别将左右两个串以 ‘+’ 进行拆分,得到一个个的化学式
  第二步:提取化学式最外面的倍数,比如3H2O,需要提取3,需要对内部元素都乘以3。
  第三步:dfs单独对一个化学式进行处理,为什么要用dfs?因为化学式会出现括号嵌套的情况,需要dfs对每个括号单独处理。注意需要记录倍数,下一次要将倍数计算好后传入,每一次计数都需要对倍数进行处理。
细节:
  1、元素为一个大写或者一个大写一个小写
  2、多层括号嵌套
  3、括号后面的数字,需要转换为倍数传入
  4、时刻注意防止越界
  5、对空串单独判断

复杂度分析:对一个字符串扫一遍为O(len) ,由于含有括号,需要对字符串进行切割,字符串切割复杂度为O(len),所以每一个字符串处理复杂度为O(len2),map复杂度为O(mlog2(m))小于O(len2),复杂度取大的。n个字符串,总复杂度为O(n(len2))

代码(有注释):

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false)
#define ll long long
#define maxn 1005
#define inf 1000000000

//对字符串分割,分隔符为sp
vector<string> split_str(string str,char sp)
{
    vector<string>V;
    for(int i=0; i<str.size();)
    {
        string ss="";
        while(i<str.size()&&str[i]!=sp)
        {
            ss.push_back(str[i]);
            i++;
        }
        i++;
        if(ss!="")
            V.push_back(ss);
    }
    return V;
}

//将string形式的数字转换为Int
int get_num(string num)
{
    int num1=0;
    int ten=1;
    for(int k=num.size()-1; k>=0; k--)
    {
        num1+=(num[k]-=48)*ten;
        ten*=10;
    }
    return num1;
}

/**
    对单个化学式进行计数:
    利用dfs对括号进行拆解,同时记录每次记录倍数
    对于非括号内的,直接计数即可(当然要乘以倍数)
    比如 4AL(Au(CN)2)3  下一次dfs将传入 Au(CN)2 传入倍数3
**/
void dfs(map<string,int>&m1,string str,int num1)
{
    for(int k=0; k<str.size();)
    {
        if(str[k]=='(')
        {
            k++;
            int num_c=1,num_f=0;
            int j;
            for(j=k; j<str.size(); j++)
            {
                if(str[j]=='(')
                    num_c++;

                if(str[j]==')')
                {
                    num_f++;
                    if(num_f==num_c)
                        break;
                }
            }

            int len=j-k;

            string num="";
            j++;
            for(; j<str.size(); j++)
            {
                if(str[j]>='0'&&str[j]<='9')
                    num.push_back(str[j]);
                else
                    break;
            }
            int num2=1;
            if(num!="")
                num2=get_num(num);
            //cout<<"k="<<k<<",len="<<len<<",str="<<str.substr(k,len)<<",num1="<<num1*num2<<"\n";
            dfs(m1,str.substr(k,len),num1*num2);
            //cout<<num<<"\n";
            k+=len+num.size()+1;
            //cout<<"k="<<k<<"\n";
        }
        else
        {
            string xx="";
            xx.push_back(str[k]);

            if(k+1<str.size()&&str[k+1]>='a'&&str[k+1]<='z')
            {
                xx.push_back(str[k+1]);
                k++;
            }
            k++;
            string num="";
            while(k<str.size()&&str[k]>='0'&&str[k]<='9')
            {
                num.push_back(str[k]);
                k++;
            }
            int num2=1;
            if(num!="")
                num2=get_num(num);

            m1[xx]+=num2*num1;
        }
    }
}

/**
    1、对化学方程式左边或者右边进行处理
    2、处理化学式初始倍数,如4AL(Au(CN)2)3 初始倍数为最前面的4
    3、分别处理每个化学式 dfs
**/
void get_map(map<string,int>&m1,vector<string>&V1)
{
    for(int j=0; j<V1.size(); j++)
    {
        string strid=V1[j];
        string num="";
        for(int k=0; k<V1[j].size(); k++)
        {
            if(V1[j][k]>='0'&&V1[j][k]<='9')
                num+=V1[j][k];
            else
                break;
        }
        int num1;
        if(num!="")
        {
            reverse(V1[j].begin(),V1[j].end());
            for(int k=0; k<num.size(); k++)
                V1[j].pop_back();
            reverse(V1[j].begin(),V1[j].end());
            //cout<<V1[j]<<" ";
            num1=get_num(num);
        }
        else
            num1=1;

        dfs(m1,V1[j],num1);

    }
}

//判断两个map是否相等
bool equal_map(map<string,int>&m1,map<string,int>&m2)
{
    return m1==m2;
}

//打印map
void print_map(map<string,int>&m1)
{
    for(map<string,int>::iterator p=m1.begin(); p!=m1.end(); p++)
        {
            cout<<(*p).first<<","<<(*p).second<<"\n";
        }
    cout<<"---------------\n";
}

int main()
{
    IOS;
    ll n;
    cin>>n;

    for(int i=1; i<=n; i++)
    {
        map<string,int>m1,m2;

        string str;
        cin>>str;
        vector<string>V=split_str(str,'=');
        vector<string>V1=split_str(V[0],'+');
        vector<string>V2=split_str(V[1],'+');
        get_map(m1,V1);
        get_map(m2,V2);
        /*cout<<"m1:\n";
        print_map(m1);
        cout<<"m2:\n";
        print_map(m2);*/
        if(equal_map(m1,m2))
            cout<<"Y\n";
        else
            cout<<"N\n";
    }
    return 0;
}

后记:此题模了两小时,CCF大模拟题果然名不虚传

发布了41 篇原创文章 · 获赞 2 · 访问量 1196

猜你喜欢

转载自blog.csdn.net/qq_41418281/article/details/104080944
今日推荐