2 条题解
-
0
这是一个用于生成 B3940 [GESP样题 四级] 填幻方 测试数据的完整 C++ 代码。
由于题目中 的范围是 且 为奇数,所有可能的输入值恰好有 10 个(3, 5, 7, ..., 21)。因此,这个生成器会将这 10 个可能的 值分别作为 1 到 10 号测试点,从而实现对所有情况的完全覆盖。
数据生成器代码 (generator.cpp)
您可以将以下代码保存为
generator.cpp,编译并运行。它将在当前目录下生成1.in/1.out到10.in/10.out。#include <iostream> #include <fstream> #include <vector> #include <string> #include <iomanip> using namespace std; // ========================================== // 1. 标准解法函数 (用于生成 .out 文件) // ========================================== void solve(int N, ofstream &fout) { // 使用 vector 动态调整大小,初始化为 0 vector<vector<int>> magic(N, vector<int>(N, 0)); // 1. 在第一行的正中央填上 1 int row = 0; int col = N / 2; magic[row][col] = 1; // 循环填入 2 到 N*N for (int k = 2; k <= N * N; ++k) { // 计算向右上移动后的坐标 (上一行,下一列) // (row - 1 + N) % N 处理向上越界 // (col + 1) % N 处理向右越界 int next_row = (row - 1 + N) % N; int next_col = (col + 1) % N; // 检查移动后的位置是否为空 if (magic[next_row][next_col] == 0) { // 如果为空,确认移动到该位置 row = next_row; col = next_col; } else { // 如果不为空,则从"上次填数字的位置"向下移动一格 row = (row + 1) % N; // col 保持不变 } // 填入数字 magic[row][col] = k; } // 输出幻方到文件 for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { fout << magic[i][j] << (j == N - 1 ? "" : " "); } fout << "\n"; } } // ========================================== // 2. 测试点生成逻辑 // ========================================== void generate_test_case(int id) { // 题目要求 N 为奇数,且 3 <= N <= 21 // 可能的 N 值为: 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 // 恰好 10 个,直接映射 id 1~10 到这些值 int N = 2 * id + 1; // --- 写入 .in 文件 --- string in_filename = to_string(id) + ".in"; ofstream fin(in_filename); fin << N << "\n"; fin.close(); // --- 计算答案并写入 .out 文件 --- string out_filename = to_string(id) + ".out"; ofstream fout(out_filename); solve(N, fout); fout.close(); cout << "Generated Case " << id << ": N=" << N << endl; } int main() { // 生成 1 到 10 号测试点 for (int i = 1; i <= 10; ++i) { generate_test_case(i); } cout << "All test cases generated successfully!" << endl; return 0; }测试点覆盖说明
本生成器采用了全覆盖策略,因为题目数据范围较小且离散:
- Case 1: (题目样例,最小边界)
- Case 2:
- Case 3:
- Case 4:
- Case 5: (中等规模)
- Case 6:
- Case 7:
- Case 8:
- Case 9:
- Case 10: (最大边界)
每个测试点都严格遵循题目描述的“罗伯法”(Loubère method)生成标准答案。
使用方法
- 保存:将代码保存为
generator.cpp。 - 编译:使用 C++ 编译器编译(如
g++ generator.cpp -o generator)。 - 运行:运行生成的可执行文件(如
./generator或generator.exe)。 - 结果:当前目录下会生成 10 组
.in和.out文件,可直接上传至 OJ 系统。
-
0
这是一个经典的构造奇数阶幻方的问题,所描述的方法被称为“罗伯法”(Loubère method)。
题目分析
- 输入:一个正奇数 ()。
- 目标:构造并输出一个 的幻方。
- 规则:
- 数字 1 放在第一行的正中间。
- 下一个数字填在当前位置的右上方(行号减1,列号加1)。注意处理边界的“回绕”情况:
- 如果行号减1后小于0,则变到最后一行。
- 如果列号加1后超过最大列索引,则变到第一列。
- 冲突处理:如果右上方的位置已经填了数字,则改为填在当前位置的正下方(行号加1)。
算法实现
我们可以使用一个二维数组
a[N][N]来存储幻方。 设当前数字的位置为 。 对于下一个数字 ():- 计算预想位置:
next_row = (row - 1 + N) % N,next_col = (col + 1) % N。- 这里
(row - 1 + N) % N可以巧妙地处理向上越界回到最后一行的情况。 (col + 1) % N可以处理向右越界回到第一列的情况。
- 这里
- 检查
a[next_row][next_col]是否为 0(即是否为空)。- 若为空,则 填入该位置,更新
row = next_row,col = next_col。 - 若不为空,则 填入当前位置的正下方:
row = (row + 1) % N,col不变。
- 若为空,则 填入该位置,更新
C++ 代码
#include <iostream> #include <vector> using namespace std; int main() { int N; if (!(cin >> N)) return 0; // 定义一个二维数组,初始化为0 // N 最大为 21,开 25x25 足够 int magic[25][25] = {0}; // 1. 在第一行的正中央填上 1 // 行下标从 0 开始,列下标从 0 到 N-1 int row = 0; int col = N / 2; magic[row][col] = 1; // 循环填入 2 到 N*N for (int k = 2; k <= N * N; ++k) { // 计算向右上移动后的坐标 // (row - 1 + N) % N 实现向上移动并在越界时回到最后一行 // (col + 1) % N 实现向右移动并在越界时回到第一列 int next_row = (row - 1 + N) % N; int next_col = (col + 1) % N; // 检查移动后的位置是否为空 if (magic[next_row][next_col] == 0) { // 如果为空,确认移动到该位置 row = next_row; col = next_col; } else { // 如果不为空,则从"上次填数字的位置"向下移动一格 row = (row + 1) % N; // col 保持不变 } // 填入数字 magic[row][col] = k; } // 输出幻方 for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { cout << magic[i][j] << (j == N - 1 ? "" : " "); } cout << endl; } return 0; }
- 1
信息
- ID
- 14673
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- 3
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者