原理

暴力枚举所有的情况,运算符号4个,加减乘除 + - * / ,整数数字4个(易扩展为5个数或者更多)。所需要枚举的次数:

  1. 数字顺序:4个数的全排列,4! = 24
  2. 运算符号:4个数需要3个符号,每个可选4种,43 = 64
  3. 加括号方式:((AB)C)D(A(BC))D(AB)(CD)A((BC)D)A(B(CD)),共5种。
  4. 枚举次数 24*64*5

实现细节

  • 全排列枚举由库函数 next_permutation来完成枚举
  • 64种运算符号搭配由一个整数状压(0—63)来完成枚举
  • 加括号方式由后缀表达式来完成,运算对象用0表示,运算符用1表示,由右向左开始,以(A-(B+C))*D为例,转成后缀表达式为ABC+-D*,改成由右向左阅读的顺序,*D-+CBA,再转成用01标记的二进制数1011000,为了在代码中便于对运算符和运算对象同时操作,去掉最后一个0,变为101100,去掉的那个在初始时提前压栈,这样就正好3个0、3个1了,同理,((AB)C)D->101010(AB)(CD)->110010A((BC)D)->110100A(B(CD))->111000
  • 由于运算过程中含有除法,用double又不是我风格,所以写个小结构体表示有理数。包含分子和分母。
  • 验证是否有解和打印解分开,更灵活。

代码

运算过程和模拟计算后缀表达式差不多,一个原理。

#include <bits/stdc++.h>
#define top_and_pop(stack, var) var=stack.top();stack.pop()
using namespace std;
//运算 + - * / , 数量 num_n = 4
const int num_n = 4, max_oper = 1 << (2*num_n - 2);
struct Num {int a, b;Num(int ta = 0, int tb = 1) : a(ta), b(tb) {if(b < 0)a = -a, b = -b;int g = __gcd(abs(a), b);a /= g, b /= g;}
};
// 候选的后缀表达式所代表的整数值
int methods[5] = {0b101010, 0b101100, 0b110010, 0b110100, 0b111000};
bool hasAnswer(int* arr, int oper_code, int method) {stack<int> ops;stack<Num> nums;int arr_pos = 0;nums.push(Num(arr[arr_pos++]));while(method) {if(method & 1) {Num x,y;top_and_pop(nums, y);top_and_pop(nums, x);switch(ops.top()) {case 0: // +nums.push({x.a * y.b + x.b * y.a, x.b * y.b});break;case 1: // -nums.push({x.a * y.b - x.b * y.a, x.b * y.b});break;case 2: // *nums.push({x.a * y.a, x.b * y.b});break;case 3: // /if(y.a == 0)return false;nums.push({x.a * y.b, x.b * y.a});break;}ops.pop();} else {nums.push(Num(arr[arr_pos++]));ops.push(oper_code & 3);oper_code >>= 2;}method >>= 1;}return nums.top().a == 24 && nums.top().b == 1;
}
void printAnswer(int* arr, int oper_code, int method) {const char* operstr = "+-*/";string zuo = "(", you = ")", s1, s2;stack<char> ops;stack<string> str;int arr_pos = 0;str.push(to_string(arr[arr_pos++]));while(method) {if(method & 1) {top_and_pop(str, s2);top_and_pop(str, s1);str.push(zuo + s1 + ops.top() + s2 + you);ops.pop();} else {str.push(to_string(arr[arr_pos++]));ops.push(operstr[oper_code & 3]);oper_code >>= 2;}method >>= 1;}string res = str.top();cout << res.substr(1, res.length() - 2) << endl;
}
int arr[num_n]; // 4 个数字
int main() {int t;cin >> t;
outer_loop:while(t--) {for(int i = 0; i < num_n; i++) {cin >> arr[i];}sort(arr, arr + num_n);do {for(int meth : methods) {for(int oper = 0; oper < max_oper; oper++) {if(hasAnswer(arr, oper, meth)) {printAnswer(arr, oper, meth);goto outer_loop; // break multiloop}}}} while(next_permutation(arr, arr + num_n));cout << "No solution" << endl;}
}

测试

注: 第一个数是测试组数

扩展

上述代码可以很容易的扩展成多个数字,比如对5个数字进行24点计算。把 num_n 改为5,然后再修改一下 methods 数组为

int methods[14] = {0b10101010,0b10101100,0b10110010,0b10110100,0b10111000,0b11001010,0b11001100,0b11010010,0b11010100,0b11011000,0b11100010,0b11100100,0b11101000,0b11110000};

其中14就是5个数字加括号一共的种类数,他是卡特兰数。其实上面那一串二进制数是有规律的,所以可以写代码来生成,而不需要手算。
其实,也可以写成递归版的,就不需要算这些后缀表达式了。改天写一写。

5个数24点测试

C++ 实现计算24点相关推荐

  1. 24点游戏java_使用java编写计算24点游戏程序

    初学java,编写了一个计算24点的程序,时间有限,有些粗糙,不过可以使用. //-------------Cal24.java--------------- //计算24点程序 //作者:徒步天下( ...

  2. c#和javascript分别轻松实现计算24点

    24点游戏介绍:给出4个1-9之间的整数(ms我当年玩的时候是用扑克牌),其中每个数字必须且只用一次:任意使用+-*/ ( ),构造出一个表达式,使得最终结果为24,这就是常见的算24点的游戏(我的老 ...

  3. 计算机公式求时间差公式,24时间差计算公式 excel中计算24小时

    excel中计算24小时制时间差 怎样在excel中计算24小时制时间差,在一天之内的小编会,不过不在一天之内外套一个MOD函数,就行了,这样试试 =MOD("0:36"-&quo ...

  4. 1224 红魔馆的纸牌游戏 (计算24点,dfs)

    Description 红魔馆的蕾米莉亚大小姐一天发现人类有一种叫做24点的游戏,于是就带着一副不知哪里弄来的扑克牌到图书馆找帕秋莉玩 24点游戏的规则:从一副牌中随机抽取4张牌,牌的点数为1到13之 ...

  5. 阿里云云计算 24 SLB的概念

    阿里云云计算 24 SLB的概念 参考 https://edu.aliyun.com/lesson_547_21891#_21891

  6. 使用Scala语言开发GUI界面的计算24点的游戏应用

    今年开始学习Scala语言,对它的强大和精妙叹为观止,同时也深深感到,要熟练掌握这门语言,还必须克服很多艰难险阻. 这时,我就在想,如果能有一种方式,通过实际的应用实例,以寓教于乐的方式,引导我们逐步 ...

  7. 计算24点游戏精化算法剖析

    很多人都玩过这个数学味儿很浓的益智游戏:抽出4张扑克牌,牌上的点数代表四个数字,花牌视为1点(有的把J.Q.K分别视为11.12.13点),玩家中谁最先运用加减乘除四则运算,由这四个数计算出24,谁就 ...

  8. 计算24点的程序及分析过程

    计算24点的程序及分析过程 最近正在学习数据结构.和同事闲聊时,聊到了24点的问题(就是给出4个数,然后用加减剩除及括号算出24来),记得前一阵还在网上看了一道24点的题: 5 5 5 1 ,如何算出 ...

  9. Python之计算24点

    完整的代码如下: # -*- coding: utf-8 -*- import itertools#with brackets def with_brackets(lst, ops_lst):for ...

  10. 用扑克牌计算24点(c语言)

    用扑克牌计算24点 题目 答案 注意 参考 题目 答案 #include<stdio.h>float operation(float a,float b,char c) {switch(c ...

最新文章

  1. 计算机网络有限制,计算机网络中软件限制策略的应用规则有哪些
  2. ++和+的运算优先级和++i和i++混合用法解析
  3. php中文乱码问题解决方案
  4. C++11多线程编程-两个进程轮流打印1~100
  5. POJ - 1321 棋盘问题
  6. Category 特性在 iOS 组件化中的应用与管控
  7. Lambda表达式及应用
  8. react循环key值_01 React快速入门(一)——使用循环时对于‘key’报错处理
  9. 计算机文件自动备份到移动硬盘,1个让移动硬盘自动备份的简单方法!
  10. 增强型绿植植被指数_植被指数计算方法
  11. yum 报错:Another app is currently holding the yum lock; waiting for it to exit......
  12. 小技巧:机械键盘使用技巧
  13. CHD搭建的环境中,解决用户权限的问题
  14. ABOV单片机KEIL C51编译器程序仿真器OCD-II操作步骤详解
  15. 大数据来临,商业银行面对合规挑战!
  16. 计算机网络dce是什么意思,DTE与DCE的解释
  17. 从零到百亿互网融构展
  18. 摆脱伪智能困境,全方位解读车联网技术应用
  19. 模糊C均值聚类以及C实现
  20. usb hub芯片 android,usb hub芯片GL850G详解

热门文章

  1. 转载-SAP HCM系统和OA系统接口方案讨论
  2. Win7自带驱动备份功能使用教程
  3. 广告公司管理软件介绍
  4. 病毒周报(080630至080706)
  5. 简单工厂模式、工厂模式以及抽象工厂模式(具体)
  6. 金蝶账套总显示找不到服务器,金蝶KIS账套名称登录时没有显示怎么办呢
  7. 写给立志做码农的大学生
  8. Leawo Video Converter(狸窝视频转换器)V8.1.0 下载安装和激活和常见操作说明
  9. java截取视频的帧
  10. 逆战ds服务器怎么修复,IBMDS3512存储硬盘坏了正确的更换方法应该是怎么