Problem
Given a positive odd integer n
, generate a magic square of order n
(an n x n
grid) that contains the integers 1..n^2
exactly once, such that every row, every column, and both main diagonals sum to the same value — the magic constant M
.
Because the square uses each integer from 1
to n^2
exactly once, M
depends only on n
and equals:
M = n * (n*n + 1) / 2
Examples
Example 1
|
|
Example 2
|
|
Notes
- This file focuses on odd-order magic squares (
n % 2 == 1
) and presents the classical Siamese (de la Loubère) method for constructing them. Doubly-even (n % 4 == 0
) and singly-even (n % 4 == 2
) constructions use different techniques and are covered in related problems listed above. - The magic constant
M
is always an integer for integern
becausen*(n^2+1)
is even for every integern
.
Solution
For odd n
, the classical and simple method is the Siamese (de la Loubère) algorithm. It constructs the magic square by placing successive integers while moving in a fixed pattern (up and right) and wrapping around the grid, with a single rule to resolve collisions.
Method 1 — Siamese (de la Loubère) method
Intuition
Did you find any pattern in which the numbers are stored? In this Siamese variant the first number (1
) is placed at (i = n/2, j = n-1)
. Each subsequent number is placed by moving one row up and one column to the right (treating rows and columns as circular so they wrap around).
Two special corrections ensure correctness:
- If the tentative move goes off both the top (
i == -1
) and beyond the right edge (j == n
), reset to(0, n-2)
. - If the tentative target cell is already occupied, instead move one row down from the previous position and two columns left from the tentative position (equivalently:
i += 1; j -= 2
) and place the same number there.
These simple rules ensure every cell is filled exactly once and produce a valid odd-order magic square.
Approach
Follow these steps exactly:
- Create an
n x n
gridmat
initialized to zeros. Seti = n/2
,j = n - 1
, andnum = 1
. - While
num <= n*n
:- Tentatively set
i = i - 1
andj = j + 1
(the up-right move). - If
i == -1 && j == n
then seti = 0
andj = n - 2
. - Else if only one index is out of range, wrap it: if
i < 0
seti = n - 1
; ifj == n
setj = 0
. - If
mat[i][j] != 0
(cell already filled), undo the tentative move and seti = i + 1
,j = j - 2
and try placingnum
there (do not incrementnum
). - Otherwise set
mat[i][j] = num
and incrementnum
.
- Tentatively set
- When finished, return
mat
.
Edge cases / notes:
- This variant starts at
(n/2, n-1)
; it’s equivalent up to rotation/reflection to the common(0, n//2)
start. - Works for all odd
n
(3,5,7,…). Time and space are bothO(n^2)
.
Code
|
|
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n^2)
, because we fill then x n
grid once and then visit each cell once more to complement selected positions. - 🧺 Space complexity:
O(n^2)
, to store then x n
magic square.