一副扑克牌的每张牌表示一个数(J、Q、K 分别表示 11、12、13,两个司令都表示 6)。任取4 张牌,即得到 4 个 1~13 的数,请添加运算符(规定为加+ 减- 乘* 除/ 四种)使之成为一个运算式。每个数只能参与一次运算,4 个数顺序可以任意组合,4 个运算符任意取 3 个且可以重复取。运算遵从一定优先级别,可加括号控制,最终使运算结果为 24。请输出一种解决方案的表达式,用括号表示运算优先。如果没有一种解决方案,则输出 -1 表示无解。
输入格式:
输入在一行中给出 4 个整数,每个整数取值在 [1, 13]。
输出格式:
输出任一种解决方案的表达式,用括号表示运算优先。如果没有解决方案,请输出 -1。
输入样例:
2 3 12 12
输出样例:
((3-2)*12)+12
重要函数:
首先我们了解一下python中的permutations函数,这是一个全排列函数,可以将输入的列表中的各个元素全排列并输出:
演示
from itertools import permutations
in_list = [1, 2, 3]
print(list(permutations(in_list)))
输出结果
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
可以见到当我们输入一组数时,该函数可以将数据迅速全排列
思路
计算
我们需要一个函数来帮我们应对不同的+-*/运算,于是我定义了一个函数
def clc_with_symbol(num_a, clc_symbol, num_b):
# 符号计算器,需要 数字num_a 符号clc_symbol 数字num_b,返回浮点数
num_a = float(num_a)
num_b = float(num_b)
if clc_symbol == '+':
return num_a + num_b
elif clc_symbol == '-':
return num_a - num_b
elif clc_symbol == '*':
return num_a * num_b
elif clc_symbol == '/':
if num_b == 0:
return 99999
return num_a / num_b
有了这个函数,我们就可以使用(数字)(符号)(数字)的格式来计算当前式子的结果,美中不足的是我还没有很好的应对除数是0得到情况
运算顺序
接着,我们需要处理运算顺序和符号顺序
我们稍加思索可以的出,四个数字的计算顺序总共就5种,分别有
((x # x) # x) # x
(x # x) # (x # x)
(x # (x # x)) # x
x # ((x # x) # x)
x # (x # (x # x))
(x代表数字,#代表符号)
这个思路我使用的是排列符号和全排列数组的交叉计算
我们先利用全排列的数组的[0],[1],[2],[3]位分别放到式子的1234位,然后让排列好的符号分别填充到每个数字之间,计算是否等于24然后输出
符号排列代码:
symbol_s = ['+', '-', '*', '/'] # 符号列队,方便下面排列符号
symbol_list = []
for i in range(4):
for k in range(4):
for m in range(4):
symbol_list.append([symbol_s[i], symbol_s[k], symbol_s[m]])
其中一种计算的代码是
if clc_with_symbol(clc_with_symbol(clc_with_symbol(perm[0],symbol[0],
perm[1]),symbol[1], perm[2]), symbol[2], perm[3]) == 24:
# ((x # x) # x) # x
print(f'(({perm[0]}{symbol[0]}{perm[1]}){symbol[1]}
{perm[2]}){symbol[2]}{perm[3]}')
PS代码较长,显示不完整,以下有截屏
这段代码计算的是((x # x) # x) # x运算顺序的式子,symbol是符号组里面的一个子符号组,perm是全排列组里面的一个组
以下是全部代码
代码
from itertools import permutations
def clc_with_symbol(num_a, clc_symbol, num_b):
# 符号计算器,需要 数字num_a 符号clc_symbol 数字num_b,返回浮点数
num_a = float(num_a)
num_b = float(num_b)
if clc_symbol == '+':
return num_a + num_b
elif clc_symbol == '-':
return num_a - num_b
elif clc_symbol == '*':
return num_a * num_b
elif clc_symbol == '/':
if num_b == 0:
return 99999
return num_a / num_b
module = 1 # 锚点,module值为0表示输出所有可能的排列,module值为1表示输出一次
in_list = list(input().split())
permuted_list = list(permutations(in_list))
symbol_s = ['+', '-', '*', '/'] # 符号列队,方便下面排列符号
symbol_list = []
for i in range(4):
for k in range(4):
for m in range(4):
symbol_list.append([symbol_s[i], symbol_s[k], symbol_s[m]])
flag = 0 # 插眼
for perm in permuted_list:
for symbol in symbol_list:
if clc_with_symbol(clc_with_symbol(clc_with_symbol(perm[0], symbol[0], perm[1]), symbol[1], perm[2]), symbol[2], perm[3]) == 24: # ((x # x) # x) # x
print(f'(({perm[0]}{symbol[0]}{perm[1]}){symbol[1]}{perm[2]}){symbol[2]}{perm[3]}')
flag = 1
if module:
break
elif clc_with_symbol(clc_with_symbol(perm[0], symbol[0], perm[1]), symbol[1], clc_with_symbol(perm[2], symbol[2], perm[3])) == 24: # (x # x) # (x # x)
print(f'({perm[0]}{symbol[0]}{perm[1]}){symbol[1]}({perm[2]}{symbol[2]}{perm[3]})')
flag = 1
if module:
break
elif clc_with_symbol(clc_with_symbol(perm[0], symbol[0], clc_with_symbol(perm[1], symbol[1], perm[2])), symbol[2], perm[3]) == 24: # (x # (x # x)) # x
print(f'({perm[0]}{symbol[0]}({perm[1]}{symbol[1]}{perm[2]})){symbol[2]}{perm[3]}')
flag = 1
if module:
break
elif clc_with_symbol(perm[0], symbol[0], clc_with_symbol(clc_with_symbol(perm[1], symbol[1], perm[2]), symbol[2], perm[3])) == 24: # x # ((x # x) # x)
print(f'{perm[0]}{symbol[0]}(({perm[1]}{symbol[1]}{perm[2]}){symbol[2]}{perm[3]})')
flag = 1
if module:
break
elif clc_with_symbol(perm[0], symbol[0], clc_with_symbol(perm[1], symbol[1], clc_with_symbol(perm[2], symbol[2], perm[3]))) == 24: # x # (x # (x # x))
print(f'{perm[0]}{symbol[0]}({perm[1]}{symbol[1]}({perm[2]}{symbol[2]}{perm[3]}))')
flag = 1
if module:
break
if flag == 1:
if module:
break
if flag == 0:
print("-1")
假设我在锚点module设置为0的情况下(输出所有可能),输入 2 3 12 12,结果为:
2 3 12 12
((3-2)*12)+12
((3-2)*12)+12
((3*12)+12)/2
((3*12)+12)/2
12-((2-3)*12)
(12/(2*3))*12
**内容过长已折叠**
(12+12)*(3-2)
(12+(12*3))/2
(12+12)/(3-2)
12*((12/3)-2)
(12*12)/(3*2)
((12*12)/3)/2
进程已结束,退出代码0
可以看到计算结果都是正确的
总结
感谢permutations,让我免去了递归的麻烦