当前位置: 首页 > news >正文

计算24点与运算符重载

十几年前写过一个算24点的程序。记得当时有点费劲,不过最后总算捣鼓出来了。前几天突然想再写一次,结果轻松地写出来了。C++,总行数不多,带命令行界面和注释共200行不到;利用了面向对象和运算符重载来简化代码。

首先谈算法。算法想清楚了,实现起来就很快;否则,一边写一边想,往往会陷入复杂。
算法就是:

  • 从4个数字中取2个数字进行计算,将计算结果和剩下的2个数字列在一起,这样就将原来的4个数字缩减为3个数字了;
  • 重复这个过程,从3个数字中取2个进行计算,就将原来的3个数字变成了2个数字;
  • 最后检测这2个数字的计算结果是否是24.

从数学上探讨一下计算机遍历的可能性:

  • 4个数字取任意2个,共6种可能;
  • 2个数字进行加减乘除的计算,共有6个结果(加乘各1个,减除各2个);
  • 所以,从4个数字,变成3个数字,共有 6x6=36 种可能(这其中可能会有重复,先不管,但在源码最后会有去重的技巧);
  • 同样的算法,从3个数字变成2个数字,共有 3*6=18 种可能;
  • 从2个数字变成1个数字,共有6种可能;
  • 所以,从4个数字变成1个数字,计算机最多遍历 36 * 18 * 6 = 3888 种可能
  • 通用的计算公式是: C(4,2) * 6 * C(3,2) * 6 * C(2,2) * 6 = 3888
  • 如果输入5个数字,就要多乘以 C(5,2)*6, 即多乘以 60 种可能

知道了算法,程序也就差不多确定了。
首先,需要写一段代码,列出所有“从N个数字中取2个数字”的可能性,即:既要列出取出的2个数字,也要保留剩下的数字;

其次,要写一段代码,算出2个数字的6种计算结果,还要把这6个计算过程保留下来;怎么保留计算过程呢?
每一个数字都有其来源,这个来源就是其计算过程,可以用string将其保留下来。
于是,很自然地就想到自定义一个 Number 类,既包含值,又用string类型保留了该数字的来源过程。
进一步又想到,如果重载了运算符,那么对Number的加减乘除操作的代码可能就非常简单了。

最后,要实现4变3、3变2、2变1的过程; 很自然想到,这个过程其实是递归的,所以只要实现一个“从N个数字的数组变为N-1个数字的数组”的函数即可,之后再将其略作改变,成为递归。

具体代码如下:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;const double TARGET_NUMBER = 24;
vector<string> Solutions;class Number {
private:double val; string exp; public:Number(double v=0, string e="") : val(v), exp(e) {}Number(double v) : val(v) {stringstream ss;ss << val;exp = ss.str();}Number(int v) : val(v) {stringstream ss;ss << val;exp = ss.str();}Number(const Number& other) {val = other.val;exp = other.exp;}void operator = (const Number& other) {if (this == &other) return;this->val = other.val;this->exp = other.exp;}friend Number operator + (Number& a, Number& b) {Number res;res.val = a.getVal() + b.getVal();stringstream ss;ss << "(" << a.getExp() << "+" << b.getExp() << ")";res.exp = ss.str();return res;}friend Number operator - (Number& a, Number& b) {Number res;res.val = a.getVal() - b.getVal();stringstream ss;ss << "(" << a.getExp() << "-" << b.getExp() << ")";res.exp = ss.str();return res;}friend Number operator * (Number& a, Number& b) {Number res;res.val = a.getVal() * b.getVal();stringstream ss;ss << "(" << a.getExp() << "*" << b.getExp() << ")";res.exp = ss.str();return res;}friend Number operator / (Number& a, Number& b) {Number res;res.val = a.getVal() / b.getVal();stringstream ss;ss << "(" << a.getExp() << "/" << b.getExp() << ")";res.exp = ss.str();return res;}double getVal() { return val; }string getExp() { return exp; }
};// original array = [a, b, restArray]
struct DataSet {Number a; Number b; vector<Number> restArray; DataSet(Number a=0, Number b=0) : a(a), b(b) {}
};vector<Number> genTwoNumResult(Number a, Number b) {vector<Number> result;result.push_back(a+b);result.push_back(a*b);result.push_back(a-b);result.push_back(b-a);result.push_back(a/b);result.push_back(b/a);return result;
}// Get 2 numbers out of one array 
// Save all the possibilities to one vector 
vector<DataSet> getTwoOutofArray(const vector<Number>& vec) {int vecSize = vec.size();vector<DataSet> result = {};if (vecSize < 2) return result;vector<pair<int, int>> indexPairs; for (int i=0; i<vecSize-1; i++) {for (int j=i+1; j<vecSize; j++) {indexPairs.push_back({i, j});}}for (pair<int,int>& p : indexPairs) {DataSet tmp(vec[p.first], vec[p.second]);for (int i=0; i<vecSize; i++) {if (i != p.first && i != p.second) {tmp.restArray.push_back(vec[i]);}}result.push_back(tmp);}return result; 
}// Recusive Function: reduce the size of array by one for one time 
void resolve(vector<Number>& array) {if (array.size() <= 0) return;if (array.size() == 1) {if (array[0].getVal() - TARGET_NUMBER < 1e-6 && TARGET_NUMBER - array[0].getVal() < 1e-6) {Solutions.push_back(array[0].getExp()); }return; }vector<vector<Number>> newArrays; vector<DataSet> middleSets = getTwoOutofArray(array);for (auto& dataSet : middleSets) {// Get 2 numbers out of one array, then the 2 numbers can generate 6 different numbers vector<Number> newNumbers = genTwoNumResult(dataSet.a, dataSet.b);for (auto& newNumber : newNumbers) {vector<Number> newArray = dataSet.restArray;newArray.push_back(newNumber);newArrays.push_back(newArray);}}for (auto& vecNum : newArrays) resolve(vecNum);
}void resolve_puzzle()
{int a=0, b=0, c=0, d=0;cout << "请输入4个数字(以空格间隔):";cin >> a >> b >> c >> d; vector<Number> vec{Number(a), Number(b), Number(c), Number(d)};Solutions = {};resolve(vec);sort(Solutions.begin(), Solutions.end());Solutions.erase(unique(Solutions.begin(), Solutions.end()), Solutions.end());for (auto& s : Solutions) cout << s << " = " << TARGET_NUMBER << endl;cout << "总共有 " << Solutions.size() << " 种方法:" << endl;
}int main()
{while (true) {resolve_puzzle();char answer = 'N';cout << "要继续吗?[Y|N]:";cin >> answer; if (answer == 'Y' || answer == 'y') continue;else break;}return 0;
}

运行效果如下:

请输入4个数字(以空格间隔):4 4 3 3
((4*3)+(4*3)) = 24
(3*((4*3)-4)) = 24
总共有 2 种方法:
要继续吗?[Y|N]:y
请输入4个数字(以空格间隔):5 5 5 1
(5*(5-(1/5))) = 24
总共有 1 种方法:
要继续吗?[Y|N]:n

不知道程序是否还有效率提高的地方。再想想。
有兴趣的读者可以试着把程序改成任意多个数字计算任意数字。

(END)

相关文章:

计算24点与运算符重载

十几年前写过一个算24点的程序。记得当时有点费劲&#xff0c;不过最后总算捣鼓出来了。前几天突然想再写一次&#xff0c;结果轻松地写出来了。C&#xff0c;总行数不多&#xff0c;带命令行界面和注释共200行不到&#xff1b;利用了面向对象和运算符重载来简化代码。 首先谈…...

MES系统智能工厂,搭上中国制造2025顺风车

MES在电子制造业中的应用日益广泛&#xff0c;越来越多的厂商已经购置或自行开发了MES&#xff0c;并将其作为“智能化工厂”。国内大大小小、各行各业都有上百个MES系统&#xff0c;还有很多的国外MES系统&#xff0c;怎么才能在MES系统公司中找到适合自己的MES&#xff1f;希…...

【LeetCode】每日一题(1)

目录 题目&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 写在最后&#xff1a; 题目&#xff1a; 这是他给出的接口&#xff1a; class Solution { public:int fillCups(vector<int>& amount) {} }; 作为一个数学学渣&#xff0c;我想不出厉害的数学算法…...

SpringCloud-Netflix学习笔记11——Hystrix实现服务降级

服务降级 是什么&#xff1f; 整体资源快不够了&#xff0c;忍痛将某些服务先关掉&#xff0c;待渡过难关&#xff0c;再开启回来。 如下图&#xff0c;在某一个时间段&#xff0c;访问服务A的请求特别多&#xff0c;而访问服务B和服务C的请求特别少&#xff0c;这时我们可以把…...

Oracle Dataguard(主库为 Oracle rac 集群)配置教程(03)—— 创建 dataguard 数据库之前的准备工作

Oracle Dataguard&#xff08;主库为 Oracle rac 集群&#xff09;配置教程&#xff08;03&#xff09;—— 创建 dataguard 数据库之前的准备工作 / 本专栏详细讲解 Oracle Dataguard&#xff08;Oracle 版本为11g&#xff0c;主库为双节点 Oracle rac 集群&#xff09;的配置…...

零代码做分析报表的bi软件才是好软件

有些数据分析软件对IT的依赖比较重&#xff0c;在制作报表的过程中需要用到SQL&#xff0c;这就导致了IT人员懂技术不懂业务&#xff0c;业务人员懂业务不懂技术&#xff0c;数据分析做来做去总是差点什么的局面。要是遇到了IT部门相对较弱的情况&#xff0c;还会加重IT负担&am…...

linux ALSA 驱动架构

一、kernel Audio驱动架构主流有两大类&#xff0c;一类是SOC Machine架构&#xff0c;另一类是simple-card架构。 MTK、QCom主要采用machine架构&#xff0c;rockchip采用simple card架构。 二、Machine架构驱动介绍 machine 架构每家平台实现并不完全相同&#xff0c;mach…...

JDK 8 JVM内存结构详解

前言 本文所介绍的是 JDK 1.8 版本&#xff0c;其他版本的 JDK 在这里并不一定正确&#xff1b;内容主要摘自周志明的《深入理解Java虚拟机》一书的关键点&#xff0c;并根据自身的理解进行记录。感兴趣的同学可以去阅读原著。 JVM 的内存结构&#xff0c;主要包括以下 5 个区…...

黑马程序员 Linux 教程

目录Linux 简介不同应用领域主流操作系统Linux 系统历史Linux 系统版本Linux 安装安装方式网卡设置安装 SSH 连接工具使用 FinalShell 连接到 LinuxLinux 和 Windows 目录结构对比Linux 目录介绍Linux 常用命令Linux 命令初体验Linux 命令使用技巧Linux 命令格式文件目录操作命…...

文件操作 -- IO

文章目录文件操作 -- IO文件 :文件路径 :文件的类型java 中的文件操作文件内容的相关操作字节流的读和写操作字符流的读和写操作代码案例代码案例一 &#xff1a;代码案例二 &#xff1a;代码案例三 &#xff1a;文件操作 – IO 文件 : 文件相比大家都不陌生把 &#xff0c; 打…...

FPGA解析串口协议帧3.0版本,增加了错误重发功能,提供仿真文件以及源码

FPGA解析串口协议帧已经发布2个版本了&#xff0c;分别如下&#xff1a; 版本1&#xff1a;点击查看版本1 版本1详细介绍了串口协议帧的帧组成和设计思想&#xff0c;但设计粗糙&#xff0c;注释不详细&#xff1b; 版本1&#xff1a;点击查看版本2 版本2优化了代码&#xff0c…...

365天深度学习训练营 第P6周:好莱坞明星识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 内部限免文章&#xff08;版权归 K同学啊 所有&#xff09;&#x1f366; 参考文章地址&#xff1a; &#x1f517;第P6周&#xff1a;好莱坞明星识别 | 365天深度学习训练营&#x1f356; 作者&#xff1a;K同学啊 | 接…...

一文读懂 Zebec Chain 的“先行网络” Nautilus 链

最近&#xff0c;Zebec 上线了 DAO 治理系统后&#xff0c;上线并通过了关于 Nautilus 链的提案&#xff0c;这也是DAO系统上线后通过的首个提案。 Nautilus 链可以被看作是Zebec Chain上线前的“先行”链&#xff0c;并且是目前行业内为数不多的以“Layer3”作为特点的模块化通…...

FuzzyMathematicalModel模糊数学模型-2-多目标模糊综合评价案例分享

主函数&#xff1a;clc, clear% 输入模糊矩阵的原型x [4700 6700 5900 8800 76005000 5500 5300 6800 600004.0 06.1 05.5 07.0 06.80030 0050 0040 0200 01601500 0700 1000 0050 0100];r muti_objective_fuzzy_analysis(x);% 各指标在决策中占的权重(专家系统&#xff0c;自…...

单链表--C语言版(从0开始,超详细解析,小白一看就会)

目录 一、前言 &#x1f34e; 为什么要学习链表 &#x1f4a6;顺序表有缺陷 &#x1f4a6; 优化方案&#xff1a;链表 二、链表详解 &#x1f350;链表的概念 &#x1f349;链表的结构组成&#xff1a;节点 &#x1f353;链表节点的连接&#xff08;逻辑结构与物理结构的区…...

cv2-特征点匹配(bf、FLANN)

cv2-特征点匹配&#xff08;bf、KNN、FLANN&#xff09; 文章目录cv2-特征点匹配&#xff08;bf、KNN、FLANN&#xff09;1. 暴力匹配法&#xff08;bf&#xff09;1.1 bf.match()1.2 bf.knnMatch()3. FLANN匹配法4. 总结1. 暴力匹配法&#xff08;bf&#xff09; &#xff08…...

基于matlab多功能相控阵雷达资源管理的服务质量优化

一、前言此示例说明如何为基于服务质量 &#xff08;QoS&#xff09; 优化的多功能相控阵雷达 &#xff08;MPAR&#xff09; 监控设置资源管理方案。它首先定义必须同时调查的多个搜索扇区的参数。然后&#xff0c;它介绍了累积检测范围作为搜索质量的度量&#xff0c;并展示了…...

立创eda专业版学习笔记(6)(pcb板移动节点)

先要看一个设置方面的东西&#xff1a; 进入设置-pcb-通用 我鼠标放到竖着的线上面&#xff0c;第一次点左键是这样选中的&#xff1a; 再点一次左键是这样选中的&#xff1a; 这个时候&#xff0c;把鼠标放到转角的地方&#xff0c;点右键&#xff0c;就会出现对于节点的选项…...

Java面试——MyBatis相关知识

目录 1.什么是MyBatis 2.MyBatis优缺点 3.MyBatis工作原理 4.MyBatis缓存模式 5.MyBatis代码相关问题 6.MyBatis和hibernate区别 1.什么是MyBatis MyBatis是一个半ORM持久层框架&#xff08;对象关系映射&#xff09;&#xff0c;基于JDBC进行封装&#xff0c;使得开发者…...

Cortex-M0编程入门

目录1.嵌入式系统编程入门微控制器是如何启动的嵌入式程序设计2.输入和输出3.开发流程4.C编程和汇编编程5.什么是程序映像6.C编程&#xff1a;数据类型7.用C语言操作外设8.Cortex微控制器软件接口标准&#xff08;CMSIS&#xff09;简介标准化内容组织结构使用方法优势1.嵌入式…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋

随着工业以太网的发展&#xff0c;其高效、便捷、协议开放、易于冗余等诸多优点&#xff0c;被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口&#xff0c;具有实时性、开放性&#xff0c;使用TCP/IP和IT标准&#xff0c;符合基于工业以太网的…...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...