24点算法

随机取四个数字,用加、减、乘、除、括号5种运算,计算结果等于二十四。

穷举法

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]}))']

# 可选的操作序列 64种:4*4*4
def getOplist(ops):
    op_list = [ops[i]+ops[j]+ops[p] for i in range(4) for j in range(4) for p in range(4)]
    return op_list
    
opt_list = getOplist('+-/*')

    
def main_all():
    cnt = 0
    no_ans = 0
    # 可重复组合数 13C4 = 715
    for nums in itertools.combinations_with_replacement([1,2,3,4,5,6,7,8,9,10], 4):
        flag = False
        cnt += 1  
        ans = "no ans"
        
        for num in itertools.permutations(nums, 4): # 4个数的排列数4!=24
            for op in opt_list: # 操作序列 64种:4*4*4
                for f in formats: #括号的组合 5种
                    try:
                        expr = f.format(num, op)
                        n = eval(expr)
                        # 这里需要注意小数点的截断
                        if 23.99 < n and n < 24.01:
                            flag = True
                            ans = expr
                            break
                    except ZeroDivisionError:
                        continue
                if flag:
                    break
            if flag:
                    break
          
        if not flag:
            no_ans += 1
        print((cnt,nums,ans))
    print(("all",cnt,"no ans",no_ans,"ans",cnt-no_ans))

main_all()                    

分析:穷举一次的遍历次数:4!435=7680,每次都是计算整个表达式,成本高。


下面的代码,读取输入,输出表达式

def main_input():
    while True:
        try:
            nums, flag = input().split(), False
            for num in itertools.permutations(nums, 4):
                for op in opt_list:
                    for f in formats:
                        try:
                            expr = f.format(num, op)
                            n = eval(expr)
                            if 23.99 < n and n < 24.01:
                                flag = True
                                print(expr)
                                break
                        except ZeroDivisionError:
                            continue
                    if flag:
                        break
                if flag:
                        break
            if flag:
                print('true')
            else:
                print('false')
        except:
            break

main_input()

二元计算

把多元运算转化为两元运算。

先从四个数中取出两个数进行运算,然后再从运算结果和其它两个数组成的三个数中取出两个数进行运算,最终得到两个数,再次进行运算,得到最终结果。

在求表达式的过程中,最难处理的就是对括号的处理,而这种思路很好的避免了对括号的处理。

import itertools

def is24(nums):
    if len(nums) == 1:
        return 23.99 < nums[0] and nums[0] < 24.01

    for i in itertools.permutations(nums, 2):
        arr = nums.copy()
        arr.remove(i[0])
        arr.remove(i[1])
                 
        if is24(arr + [i[0] + i[1]]) or is24(arr + [i[0] - i[1]]) or is24(arr + [i[0] * i[1]]) or (i[1] != 0 and is24(arr + [i[0] / i[1]])):
            return True

    return False
 
def main_all():
    cards = 4
    cnt = 0
    ans = 0
    for num in itertools.combinations_with_replacement([1,2,3,4,5,6,7,8,9,10], cards):
        nums = list(num)
        if cards>=5 and all(data==nums[0] for data in nums):
            continue
        cnt += 1  
        if is24(nums):
            ans += 1
        else:
            print((nums,"no ans"))

    print(("all",cnt,"no ans",cnt-ans,"ans",ans))

main_all()    

分析:穷举一次的遍历次数:C424C324C224=1152,为穷举法的15%。

缺陷是,需要额外的代价输出计算表达式。

统计

选取4张牌,最大数字为10,组合数为715,其中149个组合无解;如果最大数字为13,组合数为1820,其中458个组合无解。

选取5张牌,最大数字为10,组合数为1992,其中37个组合无解;如果最大数字为13,组合数为6175,其中80个组合无解。

refer

24点游戏里有哪些非常难算的题目?

https://www.zhihu.com/question/264095014/answer/2503005870

24点游戏算法

https://blog.csdn.net/hyblogs/article/details/106676393

所有1362个可解组合的所有独立解

https://www.4shu.net/solutions/allsolutions/

posted @   天下太平  阅读(419)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示