CCF CSP 201912-3 化学方程式配平【Python 满分代码】

一、题目

[题目描述]
化学方程式,也称为化学反应方程式,是用化学式表示化学反应的式子。给出- -组
化学方程式,请你编写程序判断每个方程式是否配平(也就是方程式中等号左右两边的
元素种类和对应的原子个数是否相同)。
本题给出的化学方程式由大小写字母、数字和符号(包括等号=、加号+、左圆括
号(和右圆括号))组成,不会出现其他字符(包括空白字符,如空格、制表符等)。化
学方程式的格式与化学课本中的形式基本相同(化学式中表示元素原子个数的下标用.
正常文本,如H2O写成H20),用自然语言描述如下:
●化学方程式由左右两个表达式组成,中间用一-个等号=连接,如2H2+02=2H20;
●表达式由若干部分组成,每部分由系数和化学式构成,部分之间用加号+连接,
如2H2+02、2H20;
●系数是整数或空串,如为空串表示系数为1;
●整数由一个或多个数字构成; .
●化学式由若干部分组成,每部分由项和系数构成,部分之间直接连接,如H20、
C02、Ca(0H)2、 Ba3(P04)2;
●项是元素或用左右圆括号括起来的化学式,如H、Ca、(OH)、 (P04);
●元素可以是一个大写字母,也可以是一个大写字母跟着一一个小写字母,如H、0、
Ca。
在这里插入图片描述

在这里插入图片描述

二、分析

有一天早上突然起来,发现自己想漏了一种情况…遂重新写了一份,丢进OJ测试后是满分。
写CSP的大佬们大多是用的C/C++,百度了一下,python的满分代码很少,只找到了一份281ms的代码,还有一些代码跟我之前CCF CSP 201912-3 化学方程式 【Python版】这个版本一样,其实不是超时,是想漏了——官方给的测试点并不全面,需要自己脑中穷举一波。
这道题我能想到的办法是用栈来递归下降,在python性能有限的情况下,这样写出来只需要125ms,我个人还是比较满意。虽然可能还可以继续优化,但我还是先贴出来供大家参考,欢迎大家交流指正。

三、代码部分

# -*- coding: utf-8 -*-
"""
Spyder Editor

This is a temporary script file.
"""
'''
11
Cu+As=Cs+Au
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
H2+O2=H2O
'''
class E:
    def __init__(self,in_str):
        def getNum(i,instr):
            temp_num=''
            mylen=len(instr)
            while i<mylen:
                if instr[i].isdigit():      
                    temp_num+=(instr[i])
                    i+=1
                else:
                    break
            return i,int(temp_num)     
        def apElem(indict,name,num=1):
            if name in indict:
                indict[name]+=num
            else:
                indict[name]=num
        def disUpper(indict,instr,i):
            temps=''
            sub=1
            mylen=len(instr)
            temps+=instr[i]
            i+=1
            if i>=mylen:
                apElem(indict,temps,sub)
                return i
            else:
                if instr[i].islower():
                    temps+=instr[i]
                    i+=1
                    if i>=mylen:
                        apElem(indict,temps,sub)
                        return i
                    elif instr[i].isdigit():
                        i,sub=getNum(i,instr)
                        apElem(indict,temps,sub)
                        return i 
                    else:
                        apElem(indict,temps,sub)
                        return i
                elif instr[i].isdigit():
                    i,sub=getNum(i,instr)
                    apElem(indict,temps,sub)
                    return i
                else:
                    apElem(indict,temps,sub)
                    return i
        def mergeDict(d1,d2):
            for i in d2.keys():
                if i in d1:
                    d1[i]+=d2[i]
                else:
                    d1[i]=d2[i]
        def updateCoef(dc,coef):
            for i in dc.keys():
                dc[i]*=coef
        def disBrackets(indict,instr,i):
            dt={}
            listb=[]
            listb.append(i+1)
            i+=1
            mylen=len(instr)
            while i<mylen:
                if instr[i]=='(':
                    listb.append(i+1)
                elif instr[i]==')':
                    l=listb.pop()
                    if(not listb):
                        r=i
                        ts=instr[l:r]
                        disForm(dt,ts)
                        i+=1
                        break
                i+=1
            if(i<mylen and instr[i].isdigit()):
                i,tempsub=getNum(i,instr)
                updateCoef(dt,tempsub)
            mergeDict(indict,dt)
            return i


        def disForm(indict,instr):
            fdict={}
            mycoef=-1
            i = 0
            mylen=len(instr)
            while i < mylen:
                if i==0 and instr[i].isdigit():
                    i,mycoef=getNum(i,instr)
                elif instr[i].isupper():
                    i=disUpper(fdict,instr,i)
                elif instr[i]=='(':
                    i=disBrackets(fdict,instr,i)
                else:
                    i+=1
            if mycoef!=-1:
                updateCoef(fdict,mycoef)
            mergeDict(indict,fdict)
        
        instr=in_str.split('=')
        instr_l=instr[0].split('+')
        instr_r = instr[1].split('+')
        
        dictL={}
        dictR={}
        for i in instr_l:
            disForm(dictL,i)
        for j in instr_r:
            disForm(dictR,j)

        if dictL==dictR:
            print('Y')
        else:
            print('N')
                    
n=int(input())
for i in range(n):
    e=E(input())

请点个赞吧,拜托了TAT

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值