24点游戏的递归解法和Python实现

什么是24点游戏

还记得小时候拿一副牌玩得24点游戏吗?

拿一副牌,抽去大小王后(J,Q,K记为11,12,13;用1代替A),剩下1~13这52张牌。任意抽取4张牌(称为牌组),用加、减、乘、除(可加括号,高级玩家也可用其他运算符号)把牌面上的数算成24。每张牌必须用且只能用一次。如抽出的牌是3、8、8、9,那么算式为(9-8)×8×3=24。

下面就介绍一种求解24点问题的递归思路以及给出其Python求解代码。

递归思路

递归

递归的思路便是把大的问题变小,每一步将原先要求解的问题分解成与原问题相似的规模较小的问题更小的问题,直至最后达到一个满足退出条件的简单问题,这样再一层层向上返回,便解决了原先的大规模的问题。在代码实现中,程序不断调用自身,每次调用都使问题规模变小,最后达到退出条件一层层返回直至解决原先的问题。

构成递归需具备的条件:

1.子问题须与原始问题为同样的事,且更为简单;

2.不能无限制地调用本身,须有个出口,化简为非递归状况处理。

理解它的一个非常好的例子便是阶乘。n的阶乘(记为fact(n))定义为:

n

!

=

i

=

1

n

i

=

n

(

n

1

)

(

n

2

)

.

.

.

1

n!=\prod_{i=1}^{n}i=n*(n-1)*(n-2)...*1n!=∏i=1n​i=n∗(n−1)∗(n−2)...∗1

它可以通过递归方式定义为:

若n=1 , 则fact(n)=1;

若n为大于1的整数,则fact(n)=n*fact(n-1)

这相当于给了一个退出条件(n=1的情况),和一个把问题分解为更小的同类型问题的方法(求n的阶乘变为求n乘上n-1的阶乘)。很容易验证,这样的递归定义和其本身的定义是一致的,而递归定义很容易用通过函数调用自身的程序代码实现。

24点问题的递归思路

24点问题也是同理

用四张牌求出24点也许没那么容易,但如果只有两个数,那么我们可以很容易地通过不同的运算符(例:加减乘除)得到两个数组合之后的结果。因此两个数的24点问题是一目了然的。

那么三个数呢?对于三个数a,b,c,我们可以从其中任意挑选两个数(三种挑选方式),例如a,b,之后通过加减乘除计算得到a与b组合后的数d(如果只有四则运算,a与b一定时d有a*b,a+b,a-b,b-a,a/b,b/a几种可能,当然除法首先要求分母不为0),那么d确定了之后问题便变成c与d算24点的两数问题,它们是否能得出24是一目了然的。于是对一个个分支(及所有可能的c和d)进行尝试,便能判断三个数能否以及如何得出24点。

四个数当然也可以以同样的方法变为多个三数问题,进而变成两数问题输出结果。

当然如果不止四个数也可以以同样的方法一步步使问题变小,直至缩小成两数问题达到递归的返回条件。

于是我们的算法求解如下:

1.一个将两个数a,b通过运算组合成新的数的函数f(a,b)

此函数输入两个数a,b,输出它们四则运算的各种对应解及其运算符。

例如输入(a,b),输出a+b的结果及加号,a-b的结果及减号…

2.递归主程序

输入牌组,判断牌组长度,若为两数问题则通过f(a,b)判断能否算出24点并返回;若牌组长度大于2则任选两个数a,b;调用函数f(a,b),将其输出的数存储在一个新的牌组中(此数所对应的运算符即为当前的解决方案分支),新的牌组长度比原先的长度减一,解这个新的牌组的24点问题。

函数的Python实现

1.一个将两个数a,b通过运算组合成新的数的函数f(a,b)

在Python中可以以一个列表的形式很容易地将输出存储起来,即输入(a,b)两个数,f(a,b)返回[(a+b,’+’),(a-b,’-’),…],这里方括号代表列表,括号代表元祖的数据结构,它将运算结果和其对应的运算符放在一起。运算结果对应的运算符用字符(即’+’,’-’,…)进行输出。

2.递归主程序

牌组可用列表来保存,并记录当前列表长度用来判断,用一个全局的数组记录求解过程,即在每一个递归分支中,保存使用过的数,组合成新数的运算符等。

将牌组记为列表A,全局的数组(当前求解过程)记为temp,初始问题大小记为N,当前问题大小记为n,则主程序可以用一张图加以说明:

Python代码实现

cal24.py中代码如下:

#交换a与b

def swap(a,b):

temp=a

a=b

b=temp

return a,b

# +:0, -:1, *:2, /:3

#in:two number

#out:a tuple with result and its operator

def f(a,b):

#让a>=b

if(a

a,b=swap(a,b)

res=[]

res.append((a*b,'*'))

res.append((a+b,'+'))

res.append((a-b,'-'))

if(b!=0):

res.append((a/b,'/'))

res.append((b/a,'/'))

else:

res.append((0,'/'))

return res

#a:list,element is number

#temp:list,the solution,len=N+1

#N:dimension of initial problem

#n:len(a)

def cal(a,n,temp,N):

if(n<=2):

res=f(a[0],a[1])

for i in res:

#例(c,'+') i[0]对应c,i[1]对应'+'

temp[N+1-n]=(a[0],i[1],a[1],'=',24)

if(abs(i[0]-24)<=1E-7):

temp[0]=True

#输出求解过程

print(temp[1:])

break

return

else:

for i in range(0,n):

#若前面得到了结果则退出分支

#若注释if,则即使得到结果也会计算其他求解24点的方案

if(temp[0]==True):

break

for j in range(i+1,n):

res=f(a[i],a[j])

for k in res:

temp[N+1-n]=(a[i],k[1],a[j],k[0])

#下一步要求解的新数组

new_a=[]

for m in range(0,n):

if(m!=i and m!=j):

new_a.append(a[m])

new_a.append(k[0])

#print(new_a,n,temp[0])

#input()

cal(new_a,n-1,temp,N)

在Python shell中进行测试:

>>> a=[1,5,5,5]

>>> N=4

>>> n=4

>>> temp=N*[0]

>>> temp[0]=False

>>> cal(a,n,temp,N)

[(1, '/', 5, 0.2), (5, '-', 0.2, 4.8), (5, '*', 4.8, '=', 24)]

输出结果意思是1,5,5,5四张牌,用1除以5得到0.2,用5-0.2得到4.8,最后用4.8乘以5可以得到24

当然将cal函数的else分支的if判断注释掉之后,可以输出一个牌组的多种求解方案:

Python shell中:

>>> a=[5,6,9,8]

>>> N=4

>>> n=4

>>> temp=N*[0]

>>> temp[0]=False

>>> cal(a,n,temp,N)

[(5, '-', 9, 4), (8, '-', 4, 4), (6, '*', 4, '=', 24)]

[(5, '+', 8, 13), (9, '-', 13, 4), (6, '*', 4, '=', 24)]

[(5, '/', 8, 1.6), (6, '+', 9, 15), (1.6, '*', 15, '=', 24)]

[(5, '/', 8, 0.625), (6, '+', 9, 15), (0.625, '/', 15, '=', 24)]

[(6, '+', 9, 15), (5, '/', 8, 1.6), (15, '*', 1.6, '=', 24)]

[(6, '+', 9, 15), (5, '/', 8, 0.625), (15, '/', 0.625, '=', 24)]

[(6, '+', 9, 15), (5, '/', 15, 3.0), (8, '*', 3.0, '=', 24)]

[(6, '+', 9, 15), (5, '/', 15, 0.3333333333333333), (8, '/', 0.3333333333333333, '=', 24)]

[(6, '+', 9, 15), (8, '*', 15, 120), (5, '/', 120, '=', 24)]

[(9, '-', 8, 1), (5, '-', 1, 4), (6, '*', 4, '=', 24)]

即牌组[5,6,9,8]有多种解决方案。对于其他牌组,大家可以自行验证。

四则运算下无解的组合

最后讨论一下24点游戏在四则运算下无解的牌组

在cal24.py中定义以下函数:

#使用此函数时将 输出无解的组合

def judge(a):

temp=(n+1)*[0]

temp[0]=False

cal(a,n,temp,N)

if(temp[0]==True):

return True

else:

return False

def groupOfNoAnswer():

s=0

NoAnsGroup=[]

for i in range(1,14):

for j in range(i,14):

for k in range(j,14):

for l in range(k,14):

a=[i,j,k,l]

if(not judge(a)):

NoAnsGroup.append(tuple(a))

s+=1

return s,NoAnsGroup

这没什么东西,就是判断是否有解并遍历整个牌组的所有组合。

Python shell中我们输入

>>> s,NoAns=groupOfNoAnswer()

>>> s

458

>>> NoAns[1:10]

[(1, 1, 1, 2), (1, 1, 1, 3), (1, 1, 1, 4), (1, 1, 1, 5), (1, 1, 1, 6), (1, 1, 1, 7), (1, 1, 1, 9), (1, 1, 1, 10), (1, 1, 2, 2)]

即在四则运算下共有458种牌组得不到24点的解(当然引入别的运算符如乘方等也许可以得出解,这只需改动f(a,b)函数添加新的运算符即可)

总结

本文讨论了24点游戏的递归解法思路和Python实现,并给出了四则运算得不到24解的一些牌的组合。 掌握了这个思路,以后在家无聊和亲朋好友玩这款游戏的时候便绝对不会输了,甚至还可以故意出点带除法的难题来小小地为难一下他们呢!当别人想不出来自己再在他们惊异的眼光中给出答案的时候,会非常有成就感的!(^_^)

原文链接:https://blog.csdn.net/weixin_43700732/article/details/108957268

python 24点题目分析_24点游戏的递归解法和Python实现相关推荐

  1. 24点游戏的递归解法和Python实现

    24点游戏的递归解法和Python实现 目录 24点游戏的递归解法和Python实现 什么是24点游戏 递归思路 递归 24点问题的递归思路 Python代码实现 四则运算下无解的组合 总结 什么是2 ...

  2. python数独伪代码回溯法_数独的暴力回溯解法和Python GUI

    数独起源于18世纪初瑞士数学家欧拉等人研究的拉丁方阵,20世纪70年代,经过美国及日本学者的推广和改良,定名为数独(Sudoku),大致的意思是"独个的数字"或"只出现一 ...

  3. 2022年全国大学生数学建模竞赛E题目-小批量物料生产安排详解+思路+Python代码时序预测模型(三)

    目录 前言 一.六种物料挑选 二.周数处理 三.时序预测模型 模型预测结果 建模的部分后续将会写出,想要了解更多的欢迎加博主微信,免费获取更多细化思路+模型! 点关注,防走丢,如有纰漏之处,请留言指教 ...

  4. python选择排序从大到小_经典排序算法和Python详解之(一)选择排序和二元选择排序...

    本文源自微信公众号[Python编程和深度学习]原文链接:经典排序算法和Python详解之(一)选择排序和二元选择排序,欢迎扫码关注鸭! 扫它!扫它!扫它 排序算法是<数据结构与算法>中最 ...

  5. python抽奖教程_利用Python写一个抽奖程序,解密游戏内抽奖的秘密|python基础教程|python入门|python教程...

    https://www.xin3721.com/eschool/pythonxin3721/ 分析需求 我们先整理下思路,目标是什么?目标是要写一个抽奖程序,那么抽奖程序的核心是什么?当然是如何判断一 ...

  6. python中item是什么类型的游戏_文本冒险游戏(Python)中的Item类

    我正在用python制作一个文本冒险游戏.我有大部分的基本项目设置,如链接位置和保存功能.(我在设置save功能时有点困难,所以如果有更好的方法,请告诉我).在 现在我想做些东西.具体地说,我希望项目 ...

  7. 怎么学好python leetcode的题目太难了_为什么leetcode中的python解法过于pythonic,而忽略了算法题主要关注的复杂度问题?...

    @vczh 说的对,上leetcode就是学习算法的. 应该关心算法的复杂度,考虑代码的鲁棒性,各种edge case. 短的代码不意味着更容易理解,也不意味着效率更高. 我不反感这种一行的pytho ...

  8. 贺泓胜:2.24黄金今日走势分析操作建议,黄金原油解套指导

    黄金走势分析: 周四数据显示,美国上周初请失业金人数下降,支持了美联储必须继续提高利率以控制通胀的立场,给美元提供上涨动能,金价则继续承压,一度创年内新低至1817.30美元/盎司.周四公布的另一数据 ...

  9. 2022年全国大学生数学建模竞赛E题目-小批量物料生产安排详解+思路+Python代码时序预测模型(一)

    目录 前言 一.赛题分析 1.问题一 问题分析 物料频率 需求量 趋势

  10. python质量数据关联性分析_相关性检验之Pearson系数及python实现

    相关性检验之Pearson系数及python实现 一.Pearson相关系数 皮尔森相关系数是用来反应俩变量之间相似程度的统计量,在机器学习中可以用来计算特征与类别间的相似度,即可判断所提取到的特征和 ...

最新文章

  1. MySQL设值自动修改时间
  2. 设计模式-合成复用原则
  3. win7 系统盘下AppData文件夹中Local和Roaming分别有什么作用?
  4. jqGrid细节备注—page参数的设置
  5. 计算机网络计技术段标 实训,计算机网络技术实训报告精选.pdf
  6. Django 入门项目案例开发(中)
  7. c#sql防注入模糊查询_SQL中利用LIKE实现模糊查询的功能
  8. 三大场景,对象存储OSS带你快速上云
  9. 简单测试std::move
  10. php操作字符串(移除字符,计算字符串中字符个数,分割字符串,字符串序列化...
  11. Rust : 简单模拟交易所与参与机构
  12. QQ群群主及管理员管理流程图
  13. 速达5000维护服务器,财务软件速达5000为什么连不上服务器
  14. LayaBox---知识点
  15. 一个Android项目被360报毒的解决方案
  16. matlab基础学习——基础数学函数(持续更新)
  17. fresco 显示缩略图,不直接使用setImageURI,防止卡顿和显示不全:纯黑色或纯白色
  18. drwxr-xr-x是啥意思
  19. es if语法 script_ESLint规则中的JavaScript知识
  20. 23 期-原文 6.30

热门文章

  1. WCF技术剖析之九:服务代理不能得到及时关闭会有什么后果?
  2. android 屏幕宽高
  3. 微信怎么at所有人_变速箱报废、发动机故障、车门下沉,全新马自达3到底怎么了?...
  4. JDK神坑:JAVA中Calendar的月份Month少1
  5. 将Unity项目改为aar模块
  6. 中国·哈尔滨国际友好城市冰雪汽车挑战赛开赛
  7. nodejs 做后台的一个完整业务整理
  8. testNg官方文档
  9. 基于注解的组件扫描——Spring IOC/DI(五)
  10. c语言第11章ppt,C语言程序设计第11章xg.ppt