题解 | #24点游戏算法#
24点游戏算法
https://www.nowcoder.com/practice/fbc417f314f745b1978fc751a54ac8cb
numberlist = input().split() # 读入数据,简写为列表n[4]
# 由于涉及到括号,把运算写为后缀表达式形式,即4个数3个运算符的表达式(用长度为7的字符串列表formula表示)
# 为什么是3个运算符,因为题目只让运算符出现在两个数字之间
# 例如输入为5 6 7 8,['1','0','2','3','*','+','-']表示n[3]*n[2]+n[0]-n[1],即8*7+5-6
# 为什么不是[6,5,7,8,'*','+','-'],因为需要避免输入数据中有重复数字的情况,所以只储存数据的下标
# 为什么不是[1,0,2,3,'*','+','-'],因为python列表中元素类型必须相同,所以统一为字符串
# 24点问题转化为从['0','1','2','3','+','-','*','/']这8个元素中选7个依次填入formula后缀表达式列表
# 填充先后顺序:先看能否填充数字,不行的话再填充运算符
# 用DFS即可解题
def Calculate(formula0:list[str])->float:
# 计算后缀表达式formula0,返回一个浮点数结果
# 用列表模拟一个运算栈stack0,top0表示栈首的下标(列表尾部)
stack0 = [0.0]*len(formula0)
top0 = -1
for m0 in formula0:
try:
# 若读到数据,直接入栈
a0 = int(m0)
top0 += 1
stack0[top0] = float(numberlist[int(m0)]) # 注意formula储存是数据下标的字符形式
except:
if m0 == '+':
stack0[top0-1] += stack0[top0]
elif m0 == '-':
stack0[top0-1] -= stack0[top0]
elif m0 == '*':
stack0[top0-1] *= stack0[top0]
else:
# 注意被除数为0的情况,本来应该返回error,但考虑到题目只要求判断是否等于24,故直接返回0
if stack0[top0] == 0:
return 0.0
stack0[top0-1] /= stack0[top0]
top0 -= 1
# 输出栈首即为运算结果
return stack0[top0]
floor = 0 # DFS当前层数(取值0~6,共7层)
formula = ['']*7 # 当前后缀表达式
pickele = ['0','1','2','3','+','-','*','/'] # formula中所有可能的值
yes = 0 # 用于判断结果是否为24,是的话为1
use = [0, 0, 0, 0] # use[i]表示formula[:floor]是否出现过'i',为0表示当前层以前n[i]未被使用
dN = 0 # 表示当前层以前数字个数与运算符个数的差值,只有dN>=2当前层才能继续插入运算符
while True:
if floor < 0: # 如果找不到可能的情况了,直接退出
break
if floor < 7: # 如果formula没填充完,那就继续填充
t = -1
# 看当前层原有的值是空(t=-1)、数字(0<=t<=3)还是运算符(4<=t<=7)
for i in range(8):
if formula[floor] == pickele[i]:
t = i
break
# 如果当前层有值,那么在更新这一层的时候原有数据是要被抹掉的,所以需更新use和dN
# 分两种情况:1.当前层为数字,把该数字标记为未使用,dN-=1;2.为符号,dN+=1
if (t>=0) and (t<=3):
# 当前层为数字,把该数字标记为未使用,dN-=1
use[t] -= 1
dN -= 1
if t <= 3:
r = -1
# 看当前层还有没有可使用的数字
for i in range(t + 1, 4):
if use[i] < 1:
r = i
break
if r >= 0: # 如果有可使用的数字pickele[r],直接填充,更新use和dN
formula[floor] = pickele[r]
dN += 1
use[r] += 1
floor += 1
else: # 如果没有可使用的数字就判断有无可用的运算符
if dN >= 2: # 后缀表达式的要求,dN >= 2表示该层可以填充运算符
# 因为该层还没有填充过运算符,故直接填充第一个运算符'+',并更新use和dN
dN -= 1
formula[floor] = pickele[4]
floor += 1
else:
# 该层没有可以填充的值了,回到上一层,注意把这层的值初始化为空
formula[floor] = ''
floor -= 1
# 如果该层原本就是运算符,dN+=1,看还有没有运算符可以用
elif t != 7:
# 若还有运算符可以用,就直接填充并进入下一层(注意填充的时候dN要-1,和前面的+1抵消了所以没写)
formula[floor] = pickele[t+1]
floor += 1
else:
# 若没有运算符可用,回到上一层
dN += 1
formula[floor] = ''
floor -= 1
else: # floor>6表示formula填充完毕,看是否能凑成24点,不能凑直接回到上一层尝试其他填充方式
if Calculate(formula) == 24.0:
yes = 1
break
else:
floor -= 1
if yes == 1:
print('true')
else:
print('false')
#华为机试HJ67##24点#