-
题目描述:
给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利
-
输入描述:
输入4个int整数(数字允许重复,但每个数字仅允许使用一次,无异常数字)
-
输出描述:
返回能否得到24点,能输出true,不能输出false
-
示例1、
输入:
7 2 1 10
输出:
true
当第一次读到题目后自己的解法如下:
import itertools
while True:
try:
nums, flag = input().split(), False
for i in itertools.product('+-*/', repeat=3):
if round(eval(nums[0] + i[0] + nums[1] + i[1] + nums[2] + i[2] + nums[3])) == 24:
flag = True
break
if flag:
print('true')
else:
print('false')
except:
break
分析,此种解法只考虑到不存在括号且数据顺序不变的情况,考虑的情况太过简单!!!!!!
遇到此题首先分析题意:
24点游戏的算法,其中最主要的思想就是穷举法。所谓穷举法就是列出4个数字加减乘除的各种可能性,包括括号的算法。我们可以将表达式分成以下几种:首先我们将4个数设为a、b、c、d,其中算术符号有+,-,*,/,。其中有效的表达式有a,ab-cd,等等。列出所有有效的表达式。此题中,a、b、c、d的范围是1到10。这就需要在定义变量的时候要有限制,即变量最大是10,最小是1。这就给编程写语句带来了方便。
解题:
算法一:
24点游戏的算法,其中最主要的思想就是穷举法。所谓穷举法就是列出4个数字加减乘除的各种可能性。我们可以将表达式分成以下几种:
1、首先我们将4个数设为a,b,c,d,根据题意,每个数只使用一次,则列出四个数的所有排序组合(共有24种组合)如下:
a b c d a b d c a c b d a c d b a d b c a d c b
b a c d b a d c b c a d b c d a b d a c b d c a
c a b d c a d b c b a d c b d a c d a b c d b a
d a b c d a c b d b a c d b c a d c a b d c b a
2、再进行算术符号(+、-、*、/)的排序如下:
+ + + + + - + + * + + / + - + + - - + - * + - / + * + + * - + * * + * / + / + + / - + / * + / /
- + + - + - - + * - + / - - + - - - - - * - - / - * + - * - - * * - * / - / + - / - - / * - / /
* + + * + - * + * * + / * - + * - - * - * * - / * * + * * - * * * * * / * / + * / - * / * * / /
/ + + / + - / + * / + / / - + / - - / - * / - / / * + / * - / * * / * / / / + / / - / / * / / /
3、我们在此用d表示abcd四个数的排序,用op表示操作运算符(+-*/)的排序,列出所有可能出现的有效表达式如下所示:
d0 op0 d1 op1 d2 op2 d3
(d0 op0 d1) op1 d2 op2 d3 d0 op0 (d1 op1 d2) op2 d3 d0 op0 d1 op1 (d2 op2 d3)
(d0 op0 d1 op1 d2) op2 d3 d0 op0 (d1 op1 d2 op2 d3)
((d0 op0 d1) op1 d2) op2 d3 (d0 op0 (d1 op1 d2)) op2 d3 d0 op0 ((d1 op1 d2) op2 d3) d0 op0 (d1 op1 (d2 op2 d3))
(d0 op0 d1) op1 (d2 op2 d3)
如上多列出共11中可能性,优化后如下:
((d0 op0 d1) op1 d2) op2 d3
(d0 op0 (d1 op1 d2)) op2 d3
(d0 op0 d1) op1 (d2 op2 d3)
d0 op0 ((d1 op1 d2) op2 d3)
d0 op0 (d1 op1 (d2 op2 d3))
4、用python代码实现以上构想,代码实现如下:
import itertools
# 算子和括号的组合只存在如下五种表达式结构
formats = ['(({0[0]}{1[0]}{0[1]}){1[1]}{0[2]}){1[2]}{0[3]}',
'({0[0]}{1[0]}({0[1]}{1[1]}{0[2]})){1[2]}{0[3]}',
'({0[0]}{1[0]}{0[1]}){1[1]}({0[2]}{1[2]}{0[3]})',
'{0[0]}{1[0]}(({0[1]}{1[1]}{0[2]}){1[2]}{0[3]})',
'{0[0]}{1[0]}({0[1]}{1[1]}({0[2]}{1[2]}{0[3]}))']
while True:
try:
nums, flag = input().split(), False
for num in itertools.permutations(nums, 4):
for op in itertools.permutations('+-*/', 3):
for f in formats:
try:
if eval(f.format(num, op)) == 24:
flag = True
break
except ZeroDivisionError:
continue
if flag:
break
if flag:
break
if flag:
print('true')
else:
print('false')
except:
break
算法二:
把多元运算转化为两元运算。先从四个数中取出两个数进行运算,然后再从运算结果和其它两个数组成的三个数中取出两个数进行运算,最终得到两个数,再次进行运算,得到最终结果。在求表达式的过程中,最难处理的就是对括号的处理,而这种思路很好的避免了对括号的处理。基于这种思路的一种算法:
因为能使用的4种运算符 +- */ 都是2元运算符,所以本文中只考虑2元运算符。2元运算符接收两个参数,输出计算结果,输出的结果参与后续的计算。
由上所述,构造所有可能的表达式的算法如下:
1、将4个整数放入列表中
2、 在列表中取两个数字的排列,共有 P(4,2) 种排列。对每一个排列,
2_1、 对 +- */ 每一个运算符,
2_1_1、根据此排列的两个数字和运算符,计算结果
2_1_2、更改列表:将此排列的两个数字从列表中去除掉,将 2_1_1 计算的结果放入列表中
2_1_3、 对新的列表,重复步骤 2
2_1_4、恢复列表:将此排列的两个数字加入列表中,将 2_1_1 计算的结果从数组中去除掉
可见这是一个递归过程。步骤 2 就是递归函数。当列表中只剩下一个数字的时候,这就是表达式的最终结果,此时递归结束。
在程序中,一定要注意递归的现场保护和恢复,也就是递归调用之前与之后,现场状态应该保持一致。在上述算法中,递归现场就是指列表,2_1_2 改变列表以进行下一层递归调用,2_1_3 则恢复列表,以确保当前递归调用获得下一个正确的排列。
括号 () 的作用只是改变运算符的优先级,也就是运算符的计算顺序。所以在以上算法中,无需考虑括号。括号只是在输出时需加以考虑。
python代码实现如下:
import itertools
def is24(nums):
if len(nums) == 1:
if nums[0] == 24:
return True
else:
return False
for i in itertools.permutations(nums, 2):
arr = nums.copy()
arr.remove(i[0])
arr.remove(i[1])
try:
if is24(arr + [i[0] + i[1]]) or is24(arr + [i[0] - i[1]])\
or is24(arr + [i[0] * i[1]]) or is24(arr + [i[0] / i[1]]):
return True
except ZeroDivisionError:
continue
return False
while True:
try:
nums = list(map(int, input().split()))
if is24(nums):
print('true')
else:
print('false')
except:
break

本文介绍了24点游戏的两种算法实现。第一种通过穷举法列出所有可能的四数运算组合,包括括号的可能性;第二种算法通过两元运算递归地组合四个数字,避免了处理括号的问题。每种算法都提供了Python代码示例。
5073

被折叠的 条评论
为什么被折叠?



