【MX-J2-T0】Turtle and Equations
枚举两个方框的 3×3=9 种运算符组合,逐一计算验证是否等于 d,常数时间。
OJ: luogu
题目 ID: P10839
难度:入门
标签:枚举
日期: 2026-08-14 15:01
形式化题目
给定四个正整数
思路
先看一个可以直接验证想法的朴素解:
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-08-14 15:01
* update_at: 2026-08-14 15:05
*/
// brute.cpp:小数据暴力解,两重循环枚举两个方框的全部 3*3=9 种运算符组合,
// 与题意一一对应,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
int a, b, c, d;
// 计算 x op y。
int calc(int x, int y, char op) {
if (op == '+') return x + y;
if (op == '-') return x - y;
return x * y;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> a >> b >> c >> d;
char ops[3] = {'+', '-', '*'};
bool ok = false;
for (int i = 0; i < 3 && !ok; i++) { // 第一个方框
for (int j = 0; j < 3 && !ok; j++) { // 第二个方框
int mid = calc(a, b, ops[i]); // 先算括号内 a op1 b
if (calc(mid, c, ops[j]) == d) ok = true;
}
}
cout << (ok ? "Yes" : "No") << '\n';
return 0;
}brute.cpp 两层循环枚举第一个方框和第二个方框的各 3 种运算符,内层计算
main.cpp 采用 rbook 模板 enumerate-dynamic-loop(递归实现 n 层循环,每层从 dfs(dep) 枚举第 dep 个方框的运算符,choose[dep] 记录选择,填满两个方框后在叶子检查等式。它枚举的集合与两重循环完全相同,只是把"两层循环"抽象成通用的"每层一个选择"的递归形态。
下面这张表展示样例 2(
| 等于 27? | ||||
|---|---|---|---|---|
| + | + | 7 | 16 | 否 |
| + | - | 7 | -2 | 否 |
| + | 7 | 63 | 否 | |
| - | + | 3 | 12 | 否 |
| - | - | 3 | -6 | 否 |
| - | 3 | 27 | 是 | |
| + | 10 | 19 | 否 | |
| - | 10 | 1 | 否 | |
| 10 | 90 | 否 |
观察要点:九种组合中恰好 No;而一旦命中就可以提前输出 Yes。
代码
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-08-14 15:01
* update_at: 2026-08-14 15:05
*/
// P10839 【MX-J2-T0】Turtle and Equations
// 枚举两个方框的运算符,共有 3*3=9 种组合。
// 本解对应 rbook 模板 enumerate-dynamic-loop:
// 递归实现 n 层循环,每层从 [0, m) 中选择一个值,这里是 2 层、每层 3 种运算符。
#include <bits/stdc++.h>
using namespace std;
int a, b, c, d;
char ops[3] = {'+', '-', '*'}; // 三种可用运算符
int choose[2]; // choose[i]:第 i 个方框选中的运算符下标
// 计算 x op y。
int calc(int x, int y, char op) {
if (op == '+') return x + y;
if (op == '-') return x - y;
return x * y;
}
// 递归枚举第 dep 个方框的运算符;填满两个方框后检查 (a op1 b) op2 c == d。
bool dfs(int dep) {
if (dep == 2) {
int mid = calc(a, b, ops[choose[0]]); // 先算括号内 a op1 b
return calc(mid, c, ops[choose[1]]) == d;
}
for (int i = 0; i < 3; i++) {
choose[dep] = i;
if (dfs(dep + 1)) return true;
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> a >> b >> c >> d;
cout << (dfs(0) ? "Yes" : "No") << '\n';
return 0;
}复杂度
- 时间:枚举
种组合, 。 - 空间:常数个变量,
。
总结
这道题的核心是枚举范围极小:两个位置各 3 种选择,总方案数 enumerate-dynamic-loop 把这种"n 层循环、每层 m 个选择"的枚举抽象成递归结构,choose[dep] 记录每层选择、叶子统一检查,适合推广到层数不固定的场景。
图示解析
这张 ASCII 图展示整道题的解题路线:
题意:填两个运算符 op1, op2 ∈ {+, -, ×}
(a op1 b) op2 c == d ?
|
v
枚举规模:3 × 3 = 9 种组合,常数
|
v
brute.cpp:两层 for 枚举所有组合
|
v
main.cpp:enumerate-dynamic-loop 递归枚举
dfs(dep) 选第 dep 个方框的运算符
choose[dep] 记录选择,叶子检查等式
|
v
存在命中 → Yes,否则 → No
复杂度 O(1),空间 O(1)图中主线是"枚举量极小 → 暴力即正解 → 递归与循环两种写法枚举同一集合"。这道题真正要掌握的不是优化,而是识别"组合数很小的枚举问题"并选择一种清晰的枚举写法。