24点的变通题
题: 已知现在有四个数字a,b,c,d,在每两个数字中间插入一个计算符号组成计算式,寻找一种组合使得计算式结果等于24
输入:[a,b,c,d],如[4,7,8,2]
输出:若有解则输出true,若无解则返回false
范例:输入[4,7,8,2],可构成 4 * 7 - 8 / 2 = 24,有解,返回true
其他约束:
____计算符号可取:+ - * /,不考虑括号
____数字取值范围:[1,10]
题目分析
这道题看上去是24点游戏的变体,通过在每两个数字中间插入符号来组成计算式。我们所要做的是,寻找可行解。由于数字的顺序固定,且不存在括号,所以有4*3=12种可能出现的情况,穷举法想必是比较合适的。
思路
先用穷举法得到可能的计算式,然后对计算式进行验证,直至找到一个可行解。在验证时,由于存在乘除运算,计算时需考虑计算符号优先级。可以将有乘除号的部分视作一个整体计算。
python在处理字符串时,有split方法可以很方便地对字符串做分解。所以,我将计算式转为字符串,再用split方法将计算式分解为多个相加(减)的项。单独计算每个项的值。由于每个项中只有乘法和除法,所以从左到右计算即可。将每个项相加(减),就可以得到整个式子的值。
最后,验证ans是否为24,若找到,即可停止搜索
算法实现
# 单项计算
def pcal(p):
# 此时计算式中只存在乘除计算,乘法被表达为*,除法表达为*/
# 根据*可以将数字再分开
pp = p.split("*")
ans = 1
for i in pp:
if i[0] == "/":
# 前面带有/,表示此步为除法
ans = ans / int(i[1:(len(i))])
else:
# 不带/号,表示此步为乘法
ans = ans * int(i)
# 返回分块的计算结果
return ans
text = input().split(",")
a = text[0][1:(len(text[0]))]
b = text[1]
c = text[2]
d = text[3][0:(len(text[3])-1)]
# a (x) b (y) c (z) d
# + - * /
find = False
# 将-写成+-,/写成*/有助于后面的分解
for x in ["+","+-","*","*/"]:
if find: break
for y in ["+","+-","*","*/"]:
if find: break
for z in ["+","+-","*","*/"]:
if find: break
# 转化为字符串计算式
caltext = a + x + b + y + c + z + d
parts = caltext.split("+")
ans = 0
# 一步分解(将式子分解为相加的多项)
for p in parts:
if p[0] == "-":
# 分块计算(计算每一项),带有-号,在结果上减掉
ans = ans - pcal(p[1:(len(p))])
else:
# 分块计算(计算每一项),带有+号,在结果上加上
ans = ans + pcal(p)
if ans == 24:
find = True
# 还原可读式,打印输出
orltext = caltext.replace("+-","-")
orltext = orltext.replace("*/","/")
print(orltext)
if find:
print("true")
else:
print("false")