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

【递归完全搜索】CCC 2008 - 24点游戏Twenty-four

题目描述

“24点”是一种流行的纸牌游戏,适合四名玩家一起玩。

每位玩家有一叠面朝下的牌。每轮游戏中,四位玩家各自翻开自己牌堆的顶牌,让所有人可见。游戏目标是用这四张牌的数值(A=1,J=11,Q=12,K=13)构造一个算式,使其结果等于 242424

((A∗K)−J)∗Q((A * K) - J) * Q ((AK)J)Q
((1∗13)−11)∗12((1 * 13) - 11) * 12 ((113)11)12

例如,题目插图中的示例中,可以构造出一个算式使结果为 242424

第一个找到这种算式的玩家赢得本轮,并将这四张牌都放到自己牌堆的底部。

每个合法的算式必须:

  • 恰好使用这四张牌的数值;

  • 只能使用加法、减法、乘法或除法;

  • 可以使用括号改变运算顺序;

  • 不能将多张牌拼接成多位数(如 222444 拼成 242424 是禁止的);

  • 除法的结果必须是整数(包括算式中任意子表达式的中间结果也必须为整数)。

在某些情况下,玩家可能很久也找不到等于 242424 的表达式,甚至可能根本不存在这样的表达式。

你的任务是:给定四张牌,找到一个算式,使结果是 不超过 242424 的最大整数。

输入格式

第一行:一个整数 nnn,表示有多少组牌。

接下来每组牌包含 444 行,每行一个整数,表示一张牌的值。

输出格式

对于每组牌,输出一行一个整数,表示用这 444 张牌能组合出的、不超过 242424 的最大值。

样例输入

3
3
3
3
3
1
1
1
1
12
5
13
1

样例输出

24
4
21

提交链接

Twenty-four

思路分析

  1. 全排列枚举牌的顺序

    • 因为牌的排列顺序会影响运算结果(例如 333 - 555555 - 333 不同)。
    • 444 张牌的所有排列数为 4!=244! = 244!=24 种。
  2. 枚举运算符组合

    • 444 张牌有 333 个空隙,每个空隙可以放 + - * / 四种运算符。
    • 一共有 43=644^3 = 6443=64 种运算符组合。
  3. 枚举括号(运算顺序)

    • 四个数、三个运算符,合法的运算顺序(括号摆放方式)有 555 种:
      1. ((a op1 b) op2 c) op3 d
      2. (a op1 (b op2 c)) op3 d
      3. a op1 ((b op2 c) op3 d)
      4. a op1 (b op2 (c op3 d))
      5. (a op1 b) op2 (c op3 d)
  4. 整数除法检查

    • 除法必须整除且不能除以零,运算时要判断。
  5. 更新最大值

    • 如果某个算式结果 ≤24≤ 2424 且合法,就用它来更新最大值。

  1. 全局变量与工具函数
  • vector<char> b{'+', '-', '*', '/'}

    • 存四种运算符,方便用下标枚举。
  • int mx

    • 记录当前测试用例中最大的不超过 242424 的结果。
  • int cal(int x, char op, int y, bool &ok)

    • 执行一次二元运算 x op y
      ok 用来标记运算是否合法:
      • 如果是 / 运算,检查除数 y 是否为 0;
      • 检查是否整除 x % y == 0
    • 如果不满足条件,ok = false,表示该运算链无效。
  1. 读取数据
int t;
cin >> t;
while (t--)
{vector<int> a(4);for (int &i : a) cin >> i;
}
  • 读取 t 组测试数据。
  • 每组数据读入 4 张牌的值。
  1. 枚举牌的顺序
sort(a.begin(), a.end());
mx = 0;
do
{// ...
} while (next_permutation(a.begin(), a.end()));
  • sort 保证 next_permutation 从最小字典序开始枚举,确保不会漏掉排列。
  • next_permutation 会枚举 444 张牌的所有排列(242424 种)。
  • 每次排列会进入一次运算符与括号的枚举。
  1. 枚举运算符
for (int i = 0; i < 4; i++)
{for (int j = 0; j < 4; j++){for (int k = 0; k < 4; k++){char op1 = b[i], op2 = b[j], op3 = b[k];
  • i, j, k 分别表示三个位置的运算符,取值 0~3,对应 + - * /
  • 一共 646464 种运算符组合。
  1. 枚举括号方式并计算
  • 每种括号方式都要单独用一个 ok = true,防止上一次计算失败状态影响下一种括号结构。

(1) ((a op1 b) op2 c) op3 d

ok = true;
r = cal(cal(cal(a[0], op1, a[1], ok), op2, a[2], ok), op3, a[3], ok);
if (ok && r <= 24) mx = max(mx, r);
  • 按括号从内到外计算。

  • 如果 ok 最终还是 true,表示整个计算合法。

(2) (a op1 (b op2 c)) op3 d

ok = true;
r = cal(cal(a[0], op1, cal(a[1], op2, a[2], ok), ok), op3, a[3], ok);
if (ok && r <= 24) mx = max(mx, r);
  • 先算 (b op2 c),再算 a op1 (...)

(3) a op1 ((b op2 c) op3 d)

ok = true;
r = cal(a[0], op1, cal(cal(a[1], op2, a[2], ok), op3, a[3], ok), ok);
if (ok && r <= 24) mx = max(mx, r);
  • 先算 (b op2 c),再 (结果 op3 d),最后 a op1 (...)

(4) a op1 (b op2 (c op3 d))

ok = true;
r = cal(a[0], op1, cal(a[1], op2, cal(a[2], op3, a[3], ok), ok), ok);
if (ok && r <= 24) mx = max(mx, r);
  • 先算 (c op3 d),再 (b op2 结果),最后 a op1 (...)

(5) (a op1 b) op2 (c op3 d)

ok = true;
r = cal(cal(a[0], op1, a[1], ok), op2, cal(a[2], op3, a[3], ok), ok);
if (ok && r <= 24) mx = max(mx, r);
  • 左右两边分别算,再用 op2 连接。

参考代码

#include <bits/stdc++.h>
using namespace std;vector<char> b{'+', '-', '*', '/'};int mx;int cal(int x, char op, int y, bool &ok)
{if (op == '+')return x + y;else if (op == '-')return x - y;else if (op == '*')return x * y;else{if (y != 0 && x % y == 0)return x / y;else{ok = false;return 0;}}
}
int main()
{int t;cin >> t; // t组样例while (t--){vector<int> a(4);for (int &i : a)cin >> i;sort(a.begin(), a.end());mx = 0;do{// 枚举运算符的使用for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){for (int k = 0; k < 4; k++){char op1 = b[i], op2 = b[j], op3 = b[k]; // 三个运算符bool ok;int r;//((a op1 b) op2 c) op3 dok = true;r = cal(cal(cal(a[0], op1, a[1], ok), op2, a[2], ok), op3, a[3], ok);if (ok && r <= 24)mx = max(mx, r);//(a op1 (b op2 c)) op3 dok = true;r = cal(cal(a[0], op1, cal(a[1], op2, a[2], ok), ok), op3, a[3], ok);if (ok && r <= 24)mx = max(mx, r);// a op1 ((b op2 c) op3 d)ok = true;r = cal(a[0], op1, cal(cal(a[1], op2, a[2], ok), op3, a[3], ok), ok);if (ok && r <= 24)mx = max(mx, r);// a op1 (b op2 (c op3 d))ok = true;r = cal(a[0], op1, cal(a[1], op2, cal(a[2], op3, a[3], ok), ok), ok);if (ok && r <= 24)mx = max(mx, r);//(a op1 b) op2 (c op3 d)ok = true;r = cal(cal(a[0], op1, a[1], ok), op2, cal(a[2], op3, a[3], ok), ok);if (ok && r <= 24)mx = max(mx, r);}}}} while (next_permutation(a.begin(), a.end())); // 四个数字的排列cout << mx << endl;}return 0;
}
http://www.dtcms.com/a/331791.html

相关文章:

  • 【完整源码+数据集+部署教程】膝关节屈伸运动检测系统源码和数据集:改进yolo11-RFAConv
  • pip和dnf只下载不安装离线包
  • 沈帅波出席茅台红缨子高粱节探讨产业赋能新模式
  • Ansys FreeFlow入门:对搅拌罐进行建模
  • 【159页PPT】机械制造行业数字化转型某著名企业U8系统全解决方案(附下载方式)
  • Avalonia_SukiUI明暗主题切换时部分元素颜色不变
  • jetson orin nx(8G)烧录super系统实录
  • Ubuntu下载、安装、编译指定版本python
  • 机器学习--KNN算法
  • Linux入门指南:基础开发工具---yum/apt
  • 单北斗GNSS变形监测应用解析
  • 读《精益数据分析》:移情(Empathy)—— 验证真实需求,避免伪需求陷阱
  • 大模型工程化落地:从模型选择到性能优化的实战指南
  • C#笔记啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
  • 机器学习学习报告
  • 【博客系统测试报告】---接口自动化测试
  • AI幻觉终结之后:GPT-5开启的“可靠性”新赛道与开发者生存指南
  • JAVA中正则表达式详解
  • 前端八股文-CSS3篇
  • 考研408《计算机组成原理》复习笔记,第四章(2)——指令寻址和数据寻址
  • K8s-kubernetes(二)资源限制-详细介绍
  • 2025 年电赛 C 题 发挥部分 1:多正方形 / 重叠正方形高精度识别与最小边长测量
  • 悲观锁乐观锁与事务注解在项目实战中的应用场景及详细解析
  • 如何解决EMI中传导干扰
  • Spring-解决项目依赖异常问题
  • 【从零开始java学习|第六篇】运算符的使用与注意事项
  • 因果推断在用户流失预警的案例研究
  • 第2节:多模态的核心问题(多模态大模型基础教程)
  • 【Unity3D】Spine 3.8版本使用记录
  • 机器学习入门:从概念到实践的核心知识梳理