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()
分析:穷举一次的遍历次数:
下面的代码,读取输入,输出表达式
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()
分析:穷举一次的遍历次数:
缺陷是,需要额外的代价输出计算表达式。
统计
选取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个可解组合的所有独立解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了