2026年【江苏"信息与未来"编程思维】真题及题解(T6:桌面游戏)
题目描述
Dr. X 设计了一个双人桌面游戏,在一个 3 × 3 3 \times 3 3×3 的方格中轮流填入数字 1 , 2 , ... , 9 1, 2, \ldots, 9 1,2,...,9。现在,方格中已经填好了一部分数字,Dr. X 和 Dr. Y 按如下规则交替填入数字 (Dr. X 先填):
- 每一轮,从当前剩余未使用的数字中,找到最小的一个数字。
- 选择方格中的任意一个空位,将该数字填入。
- 换另一个人重复这一过程,当方格被填满时,游戏结束。
游戏结束后,双方计算分数的规则:
- Dr. X 的分数 x x x 等于三行数字乘积之和。
- Dr. Y 的分数 y y y 等于三列数字乘积之和。
Dr. X 和 Dr. Y 都希望拉开和对方分数的差距:Dr. X 希望最大化 x − y x - y x−y,而 Dr. Y 希望最小化 x − y x - y x−y。他们都互相知道对方都是绝顶聪明的人,一定会采取对自己最有利的策略。请你写程序预判游戏的最终结果:
- 若 Dr. X 的分数更高,输出 first \texttt{first} first;
- 若 Dr. Y 的分数更高,输出 second \texttt{second} second;
- 若两人分数相同,输出 tie \texttt{tie} tie。
输入格式
第一行输入一个整数 T T T,表示数据组数。
接下来包含 T T T 组数据。每组数据包含 3 3 3 行,每行 3 3 3 个整数,表示当前的 3 × 3 3 \times 3 3×3 方格,其中 0 0 0 表示该位置为空。输入数据保证初始方格中所有非零数字互不相同,且都在 1 1 1 到 9 9 9 之间。
输出格式
对于每组数据,输出一行字符串,表示最终结果。
输入输出样例 1
输入 1
3
1 2 3
4 5 6
7 8 0
1 4 7
2 5 8
3 6 0
1 4 7
2 5 8
0 6 0
输出 1
first
second
second
输入输出样例 2
输入 2
1
0 0 3
4 5 6
7 0 9
输出 2
tie
说明/提示
样例 1 解释
- 第一组数据中,只有一个空位,剩余数字为 9 9 9,先手只能将 9 9 9 填入右下角。此时 Dr. X 的分数为 1 × 2 × 3 + 4 × 5 × 6 + 7 × 8 × 9 = 630 1 \times 2 \times 3 + 4 \times 5 \times 6 + 7 \times 8 \times 9 = 630 1×2×3+4×5×6+7×8×9=630,Dr. Y 的分数为 1 × 4 × 7 + 2 × 5 × 8 + 3 × 6 × 9 = 270 1 \times 4 \times 7 + 2 \times 5 \times 8 + 3 \times 6 \times 9 = 270 1×4×7+2×5×8+3×6×9=270,因此先手获胜。
- 第二组数据中,只有一个空位,剩余数字同样为 9 9 9。先手填入后,Dr. X 的分数为 270 270 270,Dr. Y 的分数为 630 630 630,因此后手获胜。
- 第三组数据中,剩余数字为 3 3 3 和 9 9 9。先手必须先填入 3 3 3,后手再填入 9 9 9。无论先手如何选择位置,后手都能使自己的最终分数更高,因此后手必胜。
样例 2 解释
-
这一组的剩余数字为 1 1 1、 2 2 2、 8 8 8。先手若不把 1 1 1 填在左上角,后手就能获胜,因此先手的最优选择是先填左上角。之后后手把 2 2 2 填在第三行第二列,先手再把 8 8 8 填在第一行第二列,最终方格为:
1 8 3
4 5 6
7 2 9
此时 Dr. X 的分数为 1 × 8 × 3 + 4 × 5 × 6 + 7 × 2 × 9 = 270 1 \times 8 \times 3 + 4 \times 5 \times 6 + 7 \times 2 \times 9 = 270 1×8×3+4×5×6+7×2×9=270,Dr. Y 的分数为 1 × 4 × 7 + 8 × 5 × 2 + 3 × 6 × 9 = 270 1 \times 4 \times 7 + 8 \times 5 \times 2 + 3 \times 6 \times 9 = 270 1×4×7+8×5×2+3×6×9=270,因此平局。
数据规模
- 对于 30 % 30\% 30% 的数据,空位 0 0 0 的个数不超过 2 2 2。
- 对于 60 % 60\% 60% 的数据,空位 0 0 0 的个数不超过 5 5 5。
- 对于 100 % 100\% 100% 的数据,空位 0 0 0 的个数不超过 9 9 9, 1 ≤ T ≤ 20 1 \le T \le 20 1≤T≤20。
思路分析
- 游戏规则中,数字的填入顺序是固定 的:从剩余数字中从小到大依次填入。
因此,游戏过程可以看作:给定当前棋盘和当前步数(确定该填哪个数字),玩家选择空位填入该数字,然后交换回合。 - 棋盘只有
3×3 = 9个格子,最多9! = 362880种不同的完整填法,完全可以通过深度优先搜索(DFS) 枚举所有可能局面。 - 每一步轮到谁由步数的奇偶性决定(步数从 0 开始,偶数步为先手 Dr.X,奇数步为后手 Dr.Y)。
- 先手的目标是最大化最终分数差
x - y,后手的目标是最小化它,因此采用极小极大搜索。 - 递归函数返回从当前局面开始,双方都采取最优策略下的最终分数差。
- 叶子节点(所有空位填满)直接计算
x - y并返回。 - 复杂度为
O(n!),n ≤ 9,每组数据最多约 36 万次递归调用,T ≤ 20,运行时间充裕。
代码实现
cpp
#include <bits/stdc++.h>
using namespace std;
int b[3][3]; // 棋盘
int rem[10], remCnt; // 剩余数字(升序)及个数
int used[10]; // 数字是否已出现在初始棋盘中
// 深度优先搜索,step 表示已填入数字的个数(也是当前要填 rem[step])
int dfs(int step) {
// 所有空位填满,计算最终分数差
if (step == remCnt) {
int x = 0, y = 0;
for (int i = 0; i < 3; i++) {
int p = 1;
for (int j = 0; j < 3; j++) p *= b[i][j];
x += p; // 三行乘积之和
}
for (int j = 0; j < 3; j++) {
int p = 1;
for (int i = 0; i < 3; i++) p *= b[i][j];
y += p; // 三列乘积之和
}
return x - y;
}
int val = rem[step]; // 本轮必须填入的数字
bool isX = (step % 2 == 0); // 偶数步先手,奇数步后手
int best = isX ? -1000000000 : 1000000000; // 先手取最大,后手取最小
// 枚举所有空位
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (b[i][j] == 0) {
b[i][j] = val; // 填入数字
int child = dfs(step + 1); // 递归下一层
b[i][j] = 0; // 回溯
if (isX) {
if (child > best) best = child; // 先手最大化
} else {
if (child < best) best = child; // 后手最小化
}
}
}
}
return best;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while (T--) {
memset(used, 0, sizeof(used));
// 读入棋盘,标记已出现的数字
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cin >> b[i][j];
if (b[i][j]) used[b[i][j]] = 1;
}
}
// 收集剩余数字(升序)
remCnt = 0;
for (int i = 1; i <= 9; i++) {
if (!used[i]) rem[remCnt++] = i;
}
int diff = dfs(0); // 最优最终分数差
if (diff > 0) cout << "first\n";
else if (diff < 0) cout << "second\n";
else cout << "tie\n";
}
return 0;
}
功能分析
-
核心算法:极小极大搜索 + DFS 穷举,模拟所有合法的填数过程。
-
状态表示 :用全局二维数组
b记录棋盘,用step隐含记录当前轮到谁以及要填哪个数字。 -
效率 :最多
9!种局面,每组数据耗时极短。
更多内容请关注专栏:信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
信奥赛C++普及组CSP-J一等奖通关刷题题单及题解:
https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}
