算法演练----24点游戏

给定4个整数,数字范围在1~13之间任意使用+-*/(),构造出一个表达式,使得最终结果为24,

方法一 算法分析:加括号和取出重复表达式
# 导入精确除法模块,使得在Python2中除法运算的行为更接近Python3(Python3中除法默认是精确除法)
from __future__ import division
# 导入组合函数,用于生成给定元素的不同组合情况
from itertools import combinations
import re
import numpy as np# Solver类用于解决通过给定数字组合,利用四则运算及一些扩展运算来得到特定目标值(这里目标值默认为24)的问题
class Solver:# 定义目标值为24,即期望通过运算得到的结果target = 24# 定义可使用的运算符列表,包含常规四则运算以及扩展的重复减和重复除('--','//'),虽然在常规数学中不太常见,但这里作为一种自定义运算来丰富组合可能性ops = ['+', '-', '*', '/', '--', '//']# 类的初始化方法,接收一个参数precise_mode(默认为False),用于控制是否精确处理运算表达式中的括号等细节def __init__(self, precise_mode=False):self.precise_mode = precise_mode# solution方法是主要的对外接口,用于寻找能得到目标值的表达式,接收一个数字列表nums作为参数def solution(self, nums):result = []# 调用dimensionality_reduction方法对输入的数字列表进行降维处理(简化数字和运算组合的复杂度),得到不同的分组情况groups = self.dimensionality_reduction(self.format(nums))for group in groups:for op in self.ops:# 调用assemble方法根据给定的两个表达式(或数字)和运算符构建一个新的表达式exp = self.assemble(group[0], group[1], op)['exp']# 调用check方法检查构建的表达式计算结果是否接近(在一定精度范围内)目标值,并且确保该表达式不在结果列表中(避免重复添加)if self.check(exp, self.target) and exp not in result:result.append(exp)# 将找到的满足条件的表达式添加等于目标值的后缀,例如 "表达式 = 24" 的形式return [exp + '=' + str(self.target) for exp in result]# dimensionality_reduction方法用于对输入的表达式(或数字)列表进行降维处理,尝试通过不同的组合和运算逐步简化def dimensionality_reduction(self, nums):result = []# 如果输入的列表长度大于2,说明还有多个元素需要进一步组合运算if len(nums) > 2:# 使用group方法对nums进行分组,每次取2个元素为一组for group in self.group(nums, 2):for op in self.ops:# 调用assemble方法将每组的两个元素根据当前运算符进行组合,得到一个新的元素(包含运算后的表达式和运算符信息),与剩余元素组成新的列表继续进行降维处理new_group = [self.assemble(group[0][0], group[0][1], op)] + group[1]result += self.dimensionality_reduction(new_group)else:# 如果列表长度小于等于2,直接返回该列表作为一种基本情况(无法再进一步分解组合了)result = [nums]return result# assemble方法根据两个表达式(或数字)以及运算符构建一个新的表达式,同时处理一些特殊情况(如交换律、括号添加等)def assemble(self, exp1, exp2, op):# 如果运算符是重复减或重复除,交换两个表达式的顺序并递归调用assemble方法,将运算符还原为单减或单除进行处理(因为重复减和重复除可能是自定义的一种处理逻辑,这里转换为常规运算来构建表达式)if op == '--' or op == '//':return self.assemble(exp2, exp1, op[0])# 如果运算符是乘或除,给两个参与运算的表达式都添加括号,以明确运算顺序(按照数学运算规则,乘除运算优先级高于加减,添加括号可以更准确地体现运算顺序)if op in "*/":exp1 = self.add_parenthesis(exp1)exp2 = self.add_parenthesis(exp2)# 如果处于精确模式(precise_mode为True),根据不同运算符进一步处理括号添加情况if self.precise_mode:if op == '-':exp2 = self.add_parenthesis(exp2)elif op == '/':exp2 = self.add_parenthesis(exp2, True)# 调用convert方法对构建好的表达式进行格式转换(可能涉及一些字符串处理,比如调整运算顺序等,具体看convert方法实现),得到最终的表达式字符串exp = self.convert(exp1['exp'] + op + exp2['exp'], op)return {'op': op, 'exp': exp}# add_parenthesis方法根据条件决定是否给表达式添加括号,用于明确运算顺序或者遵循精确模式的要求@staticmethoddef add_parenthesis(exp, is_necessary=False):# 如果满足必要添加括号的条件(比如is_necessary为True且表达式不是单纯数字,或者运算符是加减),则添加括号if (is_necessary and not exp['exp'].isdigit()) or exp['op'] in "+-":result = {'exp': '(' + exp['exp'] + ')','op': exp['op']}else:result = expreturn result# check方法用于检查给定的表达式计算结果是否在一定精度范围内接近目标值,同时捕获除零异常(因为在eval运算表达式时可能出现除数为0的情况)@staticmethoddef check(exp, target, precision=0.0001):try:# 使用eval函数计算表达式的值,然后判断与目标值的差值是否小于给定精度,若小于则认为接近目标值,返回Truereturn abs(eval(exp) - target) < precisionexcept ZeroDivisionError:return False# convert方法用于对表达式字符串进行格式转换,主要涉及根据运算符调整表达式中各部分的顺序等操作@staticmethoddef convert(exp, op):# 如果运算符是加减,定义一个正则表达式模式,用于匹配包含乘除运算或者数字的部分,然后在表达式前添加正号(可能是为了统一处理符号相关逻辑)if op in "+-":pattern = r'([\+\-]((\(.+\)|\d+)[\*\/](\(.+\)|\d+)|\d+))'exp = '+' + expelse:# 如果运算符是乘除,定义另一种正则表达式模式,用于匹配乘除运算和数字部分,然后在表达式前添加乘号(同样可能是为了统一处理逻辑)pattern = r'([\*\/](\(.+?\)|\d+))'exp = '*' + exp# 使用正则表达式查找所有匹配的部分,提取并排序后拼接成新的字符串,目的可能是为了对表达式中的各运算部分进行一种规范化整理result = ''.join(sorted([i[0] for i in re.findall(pattern, exp)]))if len(result)!= len(exp):result = expreturn result[1:]# format方法将输入的数字列表转换为包含表达式和空运算符的字典列表,方便后续统一处理(将数字视为一种简单的表达式形式)@staticmethoddef format(nums):return [{'op': ' ', 'exp': str(num)} for num in nums]# group方法用于将输入的表达式(或数字)列表按照指定数量进行分组,生成不同的分组组合情况@staticmethoddef group(exp_list, counter):index_list = [i for i in range(len(exp_list))]combination = list(combinations(index_list, counter))for group1 in combination:group2 = list(set(index_list) - set(group1))yield [[exp_list[g1] for g1 in group1],[exp_list[g2] for g2 in group2]]if __name__ == "__main__":# 定义一个变量auto_input用于控制是否自动生成输入数字,如果为True则自动生成随机数字作为输入,否则手动从用户输入获取数字auto_input = Falseif auto_input:# 使用numpy的随机数生成功能,生成4个范围在1到20之间的整数作为输入数字列表customer_input = np.random.randint(1, 20, size=4).tolist()else:customer_input = []customer_input.append(input('请输入第一个数字:'))customer_input.append(input('请输入第二个数字:'))customer_input.append(input('请输入第三个数字:'))customer_input.append(input('请输入第四个数字:'))# 创建Solver类的实例,使用默认的precise_mode(False)task = Solver()# 调用solution方法寻找能得到目标值的表达式answer = task.solution(customer_input)if len(answer) == 0:print('No solution')else:for a in answer:print(a)

第二种方案:列表切片操作实现排列组合
以下代码用于获取用户输入的四个数字,不过目前处于注释状态,如果要使用,取消注释即可
a = int(input("请输入第1个数字:"))
b = int(input("请输入第2个数字:"))
c = int(input("请输入第3个数字:"))
d = int(input("请输入第4个数字:"))
list1 = [a, b, c, d]# 定义四则运算的符号列表,包含加、减、乘、除四种符号,后续将通过这些符号的不同组合来构建表达式进行运算
symbols = ["+", "-", "*", "/"]# 外层的三个嵌套循环,用于遍历所有可能的运算符号组合
# 通过三重循环可以生成所有符号的排列情况,例如:先固定第一个符号,遍历第二个和第三个符号的所有可能组合,然后再更换第一个符号,重复此过程
for s1 in symbols:for s2 in symbols:for s3 in symbols:# 内层的四层嵌套循环,用于尝试所有数字的排列组合进行运算# 通过不断改变数字的排列顺序以及结合外层循环的符号组合,来穷举所有可能的四则运算表达式情况for i in range(4):# 取出当前排列中索引为i的数字,作为第一个参与运算的数字,赋值给oneone = list1[i]# 通过列表切片操作,获取除去当前索引为i的数字后的剩余数字列表,赋值给list2# 例如:如果i为0,那么list2就是[b, c, d];如果i为1,list2就是[a, c, d],以此类推list2 = list1[0:i] + list1[i + 1:]for j in range(3):# 从剩余数字列表list2中取出索引为j的数字,作为第二个参与运算的数字,赋值给twotwo = list2[j]# 再次通过列表切片操作,获取除去当前索引为j的数字后的剩余数字列表,赋值给list3list3 = list2[0:j] + list2[j + 1:]for k in range(2):# 从剩余数字列表list3中取出索引为k的数字,作为第三个参与运算的数字,赋值给threethree = list3[k]# 通过列表切片操作获取最后一个参与运算的数字,赋值给four# 例如:如果k为0,那么four就是list3[1];如果k为1,four就是list3[0]four = (list3[0:k] + list3[k + 1:])[0]# 根据当前取出的数字和符号组合,构建一个四则运算表达式的字符串格式,后续将通过eval函数对其进行求值运算express = "(({0}{1}{2}){3}({4}){5}{6})".format(one, s1, two, s2, three, s3, four)try:# 使用eval函数对构建好的表达式字符串进行求值运算,eval函数会按照Python的运算规则解析并计算表达式result = eval(express)# 判断运算结果是否等于24,如果等于,则表示找到了满足条件的表达式if result == 24:# 输出找到的能得到24的表达式,并在表达式后面添加 " = 24" 进行标识,然后直接退出程序print(express + " = 24")# 找到结果为24的表达式后直接退出程序,避免继续不必要的循环计算exit(0)except ZeroDivisionError:# 捕获除零异常,因为在使用除法符号构建的表达式中,可能出现除数为0的情况,# 当出现这种情况时,捕获异常并跳过本次运算,继续尝试其他数字和符号的组合continue# 如果经过所有的数字排列组合和符号组合尝试后,都没有找到结果为24的表达式,则输出提示信息
print("无法算出")
#第三种itertools 模块实现排列组合
import itertools
import copy# 获取用户输入的四个数字
a = int(input("请输入第1个数字:"))
b = int(input("请输入第2个数字:"))
c = int(input("请输入第3个数字:"))
d = int(input("请输入第4个数字:"))
inputList = [a, b, c, d]listAll = []
listSignIndex = []
listSign = []
listSet = list(itertools.permutations(inputList, 4))
# 将生成的数字全排列结果转换为列表形式,并添加到listAll列表中,
# 这样listAll中就包含了输入的四个数字的所有不同排列情况
for i in listSet:listAll.append(list(i))# 该函数的功能是根据listSignIndex列表中的索引值,将对应的运算符号添加到listSign列表中
# 索引0对应 +,索引1对应 -,索引2对应 *,索引3对应 /
def changIndexToSign():for i in listSignIndex:if i == 0:listSign.append("+")elif i == 1:listSign.append("-")elif i == 2:listSign.append("*")elif i == 3:listSign.append("/")last = []# start函数用于尝试通过不同的运算组合(四则运算),利用输入的四个数字来得到结果为24的表达式
def start():global last# 遍历所有数字的排列情况(listAll列表中的每一组数字排列)for list1 in listAll:val = list1[0]  # 先取出当前排列的第一个数字作为初始值last = copy.deepcopy(list1)  # 深拷贝当前的数字排列,用于后续构建表达式字符串# 循环遍历四种运算符号,这里通过索引来对应不同的运算符号,0表示 +,1表示 -,2表示 *,3表示 /for i in range(4):if i == 0:val += list1[1]  # 如果索引为0,执行加法运算elif i == 1:val -= list1[1]  # 如果索引为1,执行减法运算elif i == 2:val *= list1[1]  # 如果索引为2,执行乘法运算elif i == 3:val /= list1[1]  # 如果索引为3,执行除法运算val2 = val  # 保存当前运算后的结果,用于内层循环结束后恢复值# 开始内层循环,再次遍历四种运算符号,用于对第三个数字进行运算for j in range(4):if j == 0:val += list1[2]elif j == 1:val -= list1[2]elif j == 2:val *= list1[2]elif j == 3:val /= list1[2]val1 = val  # 保存当前运算后的结果,用于最内层循环结束后恢复值# 最内层循环,同样遍历四种运算符号,用于对第四个数字进行运算for k in range(4):if k == 0:val += list1[3]elif k == 1:val -= list1[3]elif k == 2:val *= list1[3]elif k == 3:val /= list1[3]# 如果经过一系列运算后,结果等于24,则记录当前使用的运算符号索引if val == 24:listSignIndex.append(i)listSignIndex.append(j)listSignIndex.append(k)changIndexToSign()return  # 找到满足条件的组合后,直接返回,结束函数else:val = val1  # 如果结果不等于24,恢复到上一次内层循环运算后的结果,继续尝试其他运算符号val = val2  # 内层循环结束后,恢复到第二次运算后的结果,继续尝试其他运算符号val = list1[0]  # 外层循环每次开始时,恢复初始值,重新进行不同运算符号组合的尝试start()
listSign.append("")
lastStr = "(("
# 构建最终的表达式字符串,根据运算符号和数字的顺序进行拼接
for i in range(4):if i == 1 or i == 2:lastStr += str(last[i]) + ")" + listSign[i]else:lastStr += str(last[i]) + ")" + listSign[i]# 输出构建好的表达式字符串,并在末尾添加 =24,表示期望的结果为24
print(lastStr + "=24")输出结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于指针p有关的3个值

1&#xff0c;他的类型是int*; 2,*p是解用&#xff0c;指向的是对象 3&#xff0c;&p指向的是p的地址&#xff0c;是指针的地址

《JavaEE进阶》----20.<基于Spring图书管理系统①(登录+添加图书)>

PS&#xff1a;关于接口定义 接口定义&#xff0c;通常由服务器提供方来定义。 1.路径&#xff1a;自己定义 2.参数&#xff1a;根据需求考虑&#xff0c;我们这个接口功能完成需要哪些信息。 3.返回结果&#xff1a;考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…

Linux服务管理-iSCSI

iSCSI 基础知识 iSCSI&#xff08;Internet Small Computer System Interface&#xff09;协议是一种基于IP网络的存储协议&#xff0c;它允许主机&#xff08;计算机或服务器&#xff09;通过TCP/IP网络访问远程存储设备。该协议具有以下主要特点&#xff1a; 灵活性&#xf…

快速掌握——python类 封装[私有属性方法]、继承【python进阶】(内附代码)

1.类的定义 与 实例化对象 在python中使用class关键字创建一个类。 举例子 class Stu(object):id 1001name 张三def __init__(self):passdef fun1(self):pass# 实例化对象 s1 Stu() s2 Stu() print(s1.name) print(s2.name) 第一个方法 __init__是一种特殊的方法&#x…

HarmonyOS 如何实现传输中的数据加密

文章目录 摘要引言数据传输加密概述选择加密算法和传输协议加密实现方案与 Demo 代码配置 HTTPS/TLSAES 加密的实现代码详解RSA加密的实现代码详解 QA环节总结参考资料 摘要 本文将介绍在 HarmonyOS 应用中如何实现数据传输的加密策略。我们将讨论常见的加密算法&#xff08;如…

Bilibili-超能用户榜入口优化-技术方案反思与总结

目录 客户端实现&#xff1a; 高能用户入口实现逻辑&#xff1a; 接口服务信息&#xff08;服务端下发&#xff09;&#xff1a; 执行方案&#xff1a; (1)数据类新增服务端下发字段 ​编辑 (2) UI添加 寻找思路&#xff1a; &#xff08;3&#xff09;超能用户icon显示…

vue实现图片无限滚动播放

本人vue新手菜鸡&#xff0c;文章为自己在项目中遇到问题的记录&#xff0c;如有不足还请大佬指正 文章目录 实现效果代码展示总结 因为刚接触vue&#xff0c;本想着看看能不能用一些element的组件实现图片的轮播效果&#xff0c;尝试使用过element-UI里的走马灯Carouse&#x…

MySQL缓存使用率超过80%的解决方法

MySQL缓存使用率超过80%的解决方法 一、识别缓存使用率过高的问题1.1 使用SHOW GLOBAL STATUS命令监控1.2 监控其他相关指标二、分析缓存使用率过高的原因2.1 数据量增长2.2 查询模式变化2.3 配置不当三、解决缓存使用率过高的方法3.1 调整Buffer Pool大小3.1.1 计算合理的Buff…

LeetCode【0036】有效的数独

本文目录 1 中文题目2 求解方法&#xff1a;python内置函数set2.1 方法思路2.2 Python代码2.3 复杂度分析 3 题目总结 1 中文题目 请根据以下规则判断一个 9 x 9 的数独是否有效。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线…

UNIAPP发布小程序调用讯飞在线语音合成+实时播报

语音合成能够将文字转化为自然流畅的人声&#xff0c;提供100发音人供您选择&#xff0c;支持多语种、多方言和中英混合&#xff0c;可灵活配置音频参数。广泛应用于新闻阅读、出行导航、智能硬件和通知播报等场景。 在当下大模型火爆的今日&#xff0c;语音交互页离不开语音合…

成都睿明智科技有限公司解锁抖音电商新玩法

在这个短视频风起云涌的时代&#xff0c;抖音电商以其独特的魅力迅速崛起&#xff0c;成为众多商家争夺的流量高地。而在这片充满机遇与挑战的蓝海中&#xff0c;成都睿明智科技有限公司犹如一颗璀璨的新星&#xff0c;以其专业的抖音电商服务&#xff0c;助力无数品牌实现从零…

Llama旋转位置编码代码实现及详解

旋转位置编码RoPE 在旋转位置编码与Transformer和BERT之间的区别中介绍了旋转位置编码&#xff08;RoPE&#xff09;的特点和优势&#xff0c;这种输入长度动态可变的优势使得在Llama编码时&#xff0c;不需要掩码将多余的嵌入掩住。为了详细了解RoPE是如何实现的&#xff0c;…

遇到“msvcr120.dll丢失”要怎么解决?详解msvcr120.dll的解决方法

遇到“msvcr120.dll丢失”错误通常表明你的系统缺少一个关键的DLL文件&#xff0c;这是Microsoft Visual C 2013的一部分。这个问题可能导致某些程序无法运行&#xff0c;影响电脑性能。不过&#xff0c;解决这一问题并不复杂。接下来&#xff0c;本文将向你展示几种简单的修复…

【机器学习】平均绝对误差(MAE:Mean Absolute Error)

平均绝对误差 (Mean Absolute Error, MAE) 是一种衡量预测值与实际值之间平均差异的统计指标。它在机器学习、统计学等领域中广泛应用&#xff0c;用于评估模型的预测精度。与均方误差 (MSE) 或均方误差根 (RMSE) 不同&#xff0c;MAE 使用误差的绝对值&#xff0c;因此它在处理…

项目功能--运营数据统计

一、需求分析 通过运营数据统计可以展示出体检机构的运营情况&#xff0c;包括会员数据、预约到诊数据、热门套餐等信息。我们要通过一个表格的形式来展示这些运营数据。如下图&#xff1a; 二、代码实现 实现步骤&#xff1a; 步骤一&#xff1a;定义数据模型&#xff0c;通过…

网络安全技术在能源领域的应用

摘要 随着信息技术的飞速发展&#xff0c;能源领域逐渐实现了数字化、网络化和智能化。然而&#xff0c;这也使得能源系统面临着前所未有的网络安全威胁。本文从技术的角度出发&#xff0c;探讨了网络安全技术在能源领域的应用&#xff0c;分析了能源现状面临的网络安全威胁&a…

wangeditor富文本编辑器以文本的形式展示公式

最终展示的效果 1.首先将要传给后端的富文本值进行转化 //假设workContent是富文本写入的值this.workContent this.escapeHTML(this.workContent)//通过escapeHTML方法转化传给后端 methods:{escapeHTML(str) {return str.replace(/&/g, &amp;) // 将 & 替换为…

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪BD311R 发布时间: 2024-10-23 11:28:42 一、 产品图片&#xff1a; 二、 产品特性&#xff1a; 4G性能&#xff1a;支持2K超高清图传&#xff0c;数据传输不掉帧&#xff0c;更稳定。 独立北…

【自学笔记】神经网络(2) -- 模型评估和优化

文章目录 划分数据集训练集和测试集训练误差 测试误差交叉验证测试集 偏差与方差偏差方差表现基准 学习曲线error - train set sizeerror - degree of polynomial 数据增强迁移学习项目的完整周期样本不平衡问题精确率和召回率精确率与召回率的平衡 划分数据集 我们当然希望把所…

Windows 局域网IP扫描工具:IPScaner 轻量免安装

IPScaner是一款258KB的工具&#xff0c;具备快捷修改IP、批量扫描、地址计算等功能&#xff0c;自动识别本机IP网段&#xff0c;快速查看IP使用情况&#xff0c;适用于监控维护、企业IT运维等场 软件功能介绍&#xff1a; 1&#xff09;快捷修改本地IP、IP批量扫描、IP地址计算…