ccf 化学方程式 python 满分

5 篇文章 0 订阅
3 篇文章 0 订阅

CCF CSP 201912-3 化学方程式(python)满分
提交截图:
在这里插入图片描述

在这里插入图片描述

样例输入:

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

输出:
N
Y
N
Y
Y
Y
Y
Y
Y
Y
N

解析:每一种原子的个数是化学式前的系数与原子后的系数相乘,因为有括号的存在,难点在于如何提取系数。
思路:计算每一个原子的个数,由外向里提取系数相乘,用一个系数列表来存储每一个原子的系数,每一个原子的初始系数为化学式前的系数。例如10HNO3,那么系数列表一共有两步,
第一步:H:10,N:10,O:10
第二步:H:10,N:10,O:30
因为O原子后面跟着数字3,则第二步的时候,O:10x3
例如:32Ba((OH)2(CO3)2)3,那么系数列表的变化为:
初始化系数列表,所有元素的系数为化学式首部系数
第一步:Ba:32,O:32,H:32,C:32,O:32

遍历到左括号时,找到对应的右括号,乘以括号外的系数3,由于Ba不在括号内,所以Ba的系数不变
第二步:Ba:32,O:96,H:96,C:96,O:96

遍历到(OH)2时,对应下标的O,H元素的系数乘2
第三步:Ba:32,O:192,H:192,C:96,O:96

遍历到(CO3)2时同上,对应下标的C,O元素乘2
第四步:Ba:32,O:192,H:192,C:192,O:192

遍历到O3时,O原子后面跟着系数3,所以O元素的系数再乘3
第五步:Ba:32,O:192,H:192,C:192,O:576
计算完(CO3)2后,就没有左括号和原子了,所以系数列表就经过5步变化,之后将相同元素的个数相加即可

不明白的print(clist)就知道了

源码:

import re
# ===初始化系数列表====================================
def Cftlist(x, list):  # 系数列表
    for i in list:
        clist.append([i, x])
    return clist

m = int(input())
ceof_re=re.compile(r'\d+')
for i in range(m):
    n = input()
    left = []
    right = []
    z1 = {}
    z2 = {}
    n_l, n_r = n.split('=')
    n_l = n_l.split('+')
    n_r = n_r.split('+')
    # =========处理化学式方程式========================================
    for t in n_l, n_r:
        z3 = {}
        for j in t:
            ls = []
            k = 0
            j = j + '-'  # 字符串后加一个非字母数字的符号,防止溢出
            while k <= len(j) - 2:
                ceof_gr = ceof_re.match(j[k:])
                if str(j[k + 1]).islower():  # 处理含小写字母的元素
                    ls.append(j[k] + j[k + 1])
                    z3[j[k] + j[k + 1]] = 0  # 将元素存于字典
                    k += 2
                elif ceof_gr != None: #处理系数
                    ceof_gr = ceof_gr.group()
                    ceof = ceof_re.search(ceof_gr)[0]
                    ls.append(int(ceof))
                    k += len(ceof)
                else:
                    ls.append(j[k])
                    if str(j[k]).isalpha():  # 将化学元素存于字典
                        z3[j[k]] = 0
                    k += 1
            if t is n_l:
                left.append(ls)
                z1 = z3
            else:
                right.append(ls)
                z2 = z3
    if z1 != z2:
        print('N')
        continue
    # =========计算化学式的原子个数=============================
    clist = []
    for h in left, right:
        for v in h:
            v.append('-')  # 防止列表超出
            x = 1
            if str(v[0]).isdigit():
                x = v[0]
            clist = Cftlist(x, v)  # 初始化系数列表
            for k in range(len(v)):
                if str(v[k]).isalpha():  # 处理系数在原子后面的情况
                    if str(v[k + 1]).isdigit():
                        clist[k][1] *= v[k + 1]
                a, b = 0, 0
                if v[k] == '(':  # 处理系数在括号外的情况
                    a += 1
                    while a > 0:
                        b += 1
                        if v[k + b] == '(':
                            a += 1
                        elif v[k + b] == ')':
                            a -= 1
                    if str(v[k + b + 1]).isdigit():  # 括号内的元素的系数相乘
                        for t in range(k, k + b):
                            clist[t][1] *= v[k + b + 1]
            if h is left:  # 左边化学式的元素总数
                for t in range(len(clist)):
                    if clist[t][0] in z1:
                        z1[clist[t][0]] += clist[t][1]
            else:  # 右边化学式的元素总数
                for t in range(len(clist)):
                    if clist[t][0] in z2:
                        z2[clist[t][0]] += clist[t][1]
            #print(clist)
            clist = []

    if z1 == z2:
        print('Y')
    else:
        print('N')
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值