复赛一:神奇的幻方

洛谷:P2615
OJ: I4950

该代码使用了著名的 Siamese 方法(又称为 De la Loubère 方法)来生成奇数阶的幻方。该方法的核心思想是从幻方的第一行中间开始,按照特定的规则依次填入数字。
按四种规则生成神奇的幻方(二维数组)

代码实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**************************************************************** 
 * Description: 2015_S_semi_1  神奇的幻方
 * Author: Alex Li
 * Date: 2024-09-16 09:43:16
 * LastEditTime: 2024-09-19 14:36:36
****************************************************************/
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n; // 读取输入的 n,代表幻方的尺寸

    // 定义 MagicSqure 数组,用于存储每个数字在幻方中的位置,大小为 n*n + 1,索引从 1 开始
    vector<pair<int, int>> MagicSqure(n * n + 1);

    // 定义 squ 二维矩阵,用于存储最终的幻方,大小为 n×n,初始化为 0
    vector<vector<int>> squ(n + 1, vector<int>(n + 1, 0));

    // 初始化第一个数字 1 的位置,行位置为 0,列位置为 (n-1)/2,即中间位置
    MagicSqure[1].first = 0;
    MagicSqure[1].second = (n - 1) / 2;

    // 将数字 1 填入 squ 数组对应的位置
    squ[MagicSqure[1].first][MagicSqure[1].second] = 1;

    // 从数字 2 开始,按照题目要求的规则,逐个填入 squ 中
    for (int i = 2; i <= n * n; i++) {
        // 情况 1:如果上一个数字 (i-1) 在第一行,但不在最后一列,则将当前数字填在最后一行,上一列的右一列
        if (MagicSqure[i - 1].first == 0 && MagicSqure[i - 1].second != n - 1) {
            MagicSqure[i].first = n - 1;
            MagicSqure[i].second = MagicSqure[i - 1].second + 1;
            squ[MagicSqure[i].first][MagicSqure[i].second] = i;
        }
        // 情况 2:如果上一个数字 (i-1) 不在第一行,但在最后一列,则将当前数字填在第一列,上一行
        else if (MagicSqure[i - 1].first != 0 && MagicSqure[i - 1].second == n - 1) {
            MagicSqure[i].first = MagicSqure[i - 1].first - 1;
            MagicSqure[i].second = 0;
            squ[MagicSqure[i].first][MagicSqure[i].second] = i;
        }
        // 情况 3:如果上一个数字 (i-1) 在第一行且在最后一列,则将当前数字填在 (i-1) 的正下方
        else if (MagicSqure[i - 1].first == 0 && MagicSqure[i - 1].second == n - 1) {
            MagicSqure[i].first = MagicSqure[i - 1].first + 1;
            MagicSqure[i].second = MagicSqure[i - 1].second;
            squ[MagicSqure[i].first][MagicSqure[i].second] = i;
        }
        // 情况 4:如果上一个数字 (i-1) 既不在第一行也不在最后一列,尝试将当前数字填入右上方
        else if (MagicSqure[i - 1].first != 0 && MagicSqure[i - 1].second != n - 1) {
            // 检查右上方是否已被占用
            if (squ[MagicSqure[i - 1].first - 1][MagicSqure[i - 1].second + 1] == 0) {
                // 如果未被占用,则将当前数字填入右上方
                MagicSqure[i].first = MagicSqure[i - 1].first - 1;
                MagicSqure[i].second = MagicSqure[i - 1].second + 1;
                squ[MagicSqure[i].first][MagicSqure[i].second] = i;
            } else {
                // 否则将当前数字填入正下方
                MagicSqure[i].first = MagicSqure[i - 1].first + 1;
                MagicSqure[i].second = MagicSqure[i - 1].second;
                squ[MagicSqure[i].first][MagicSqure[i].second] = i;
            }
        }
    }

    // 输出最终构建的幻方
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cout << squ[i][j] << ' '; // 输出每个位置的数字
        }
        cout << endl; // 每行输出结束后换行
    }

    return 0;
}
Scroll to Top