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')