题解 | #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点#
全部评论

相关推荐

1 收藏 评论
分享
牛客网
牛客企业服务