24点游戏算法

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

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

  • 题目描述:

给出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
    

 

 

 

 

 

 

 

 

 

 

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值