2(2N+1) 魔方陣
December 12, 20212(2N+1) 魔方陣的維度整體來看是偶數,然而可以分解為奇數乘以偶數,例如 6 x 6 方陣,其中 6 = 2 X 3,也稱這種方陣為單偶數(oddly-even)方陣,各行、各列與各對角線的和必須相同。
解法思路
首先令 n = 2 * (2 * m + 1),並將整個方陣看靈數個奇數方陣的組合:
先依序將 A、B、C、D 四個位置,依奇數魔方陣規則填入數字,填完後方陣中各行和就相同了,但列與對角線則否,此時必須在 A-D 與 C- B 之間調換,規則如下:
- 將 A 中每列(中間列除外)頭 m 個元素,與 D 中對應位置元素調換。
- 將 A 的中央列、中央那一格向左取 m 格,並與 D 中對應位置對調。
- 將 C 中每列的倒數 m - 1 個元素,與 B 中對應元素對調。
以 6 x 6 方陣為例,先分解為奇數方陣,並填入數字:
接下來進行互換,互換的元素以不同顏色標示:
由於 m - 1 的數為 0,在這個例子中,C-B 部份不用進行對調。
程式實作
#include <stdio.h>
#include <stdlib.h>
#define N 6
#define SWAP(x,y) {int t; t = x; x = y; y = t;}
void magic_o(int [][N], int);
void exchange(int [][N], int);
int main(void) {
int square[N][N] = {0};
magic_o(square, N/2);
exchange(square, N);
int i, j;
for(i = 0; i < N; i++) {
for(j = 0; j < N; j++)
printf("%2d ", square[i][j]);
printf("\n");
}
return 0;
}
void magic_o(int square[][N], int n) {
int row = 0;
int column = n / 2;
int count;
for(count = 1; count <= n*n; count++) {
square[row][column] = count; // 填 A
square[row+n][column+n] = count + n*n; // 填 B
square[row][column+n] = count + 2*n*n; // 填 C
square[row+n][column] = count + 3*n*n; // 填 D
if(count % n == 0)
row++;
else {
row = (row == 0) ? n - 1 : row - 1 ;
column = (column == n-1) ? 0 : column + 1;
}
}
}
void exchange(int x[][N], int n) {
int m = n / 4;
int m1 = m - 1;
int i, j;
for(i = 0; i < n/2; i++) {
if(i != m) {
for(j = 0; j < m; j++) // 處理規則 1
SWAP(x[i][j], x[n/2+i][j]);
for(j = 0; j < m1; j++) // 處理規則 2
SWAP(x[i][n-1-j], x[n/2+i][n-1-j]);
}
else { // 處理規則 3
for(j = 1; j <= m; j++)
SWAP(x[m][j], x[n/2+m][j]);
for(j = 0; j < m1; j++)
SWAP(x[m][n-1-j], x[n/2+m][n-1-j]);
}
}
}
public class Matrix {
public static int[][] magic(int n) {
int[][] square = new int[n][n];
magic_o(square, n/2);
exchange(square, n);
return square;
}
private static void magic_o(int[][] square, int n) {
int row = 0;
int column = n / 2;
for(int count = 1; count <= n*n; count++) {
square[row][column] = count; // 填 A
square[row+n][column+n] = count + n*n; // 填 B
square[row][column+n] = count + 2*n*n; // 填 C
square[row+n][column] = count + 3*n*n; // 填 D
if(count % n == 0)
row++;
else {
row = (row == 0) ? n - 1 : row - 1 ;
column = (column == n-1) ? 0 : column + 1;
}
}
}
private static void exchange(int[][] x, int n) {
int m = n / 4;
int m1 = m - 1;
for(int i = 0; i < n/2; i++) {
if(i != m) {
for(int j = 0; j < m; j++) // 處理規則 1
swap(x, i, j, n/2+i, j);
for(int j = 0; j < m1; j++) // 處理規則 2
swap(x, i, n-1-j, n/2+i, n-1-j);
}
else { // 處理規則 3
for(int j = 1; j <= m; j++)
swap(x, m, j, n/2+m, j);
for(int j = 0; j < m1; j++)
swap(x, m, n-1-j, n/2+m, n-1-j);
}
}
}
private static void swap(int[][] number, int i, int j, int k, int l) {
int t = number[i][j];
number[i][j] = number[k][l];
number[k][l] = t;
}
public static void main(String[] args) {
int[][] magic = Matrix.magic(6);
for(int[] row : magic) {
for(int number: row) {
System.out.printf("%2d ", number);
}
System.out.println();
}
}
}
def magic(n):
square = []
for i in range(n):
square.append([0] * n)
magic_o(square, n // 2)
exchange(square, n)
return square
def magic_o(square, n):
row = 0
column = n // 2
for count in range(1, n ** 2 + 1):
square[row][column] = count; # 填 A
square[row + n][column + n] = count + n * n; # 填 B
square[row][column + n] = count + 2 * n * n; # 填 C
square[row + n][column] = count + 3 * n * n; # 填 D
if count % n == 0:
row += 1
else:
row = n - 1 if row == 0 else row - 1
column = 0 if column == n - 1 else column + 1
def exchange(x, n):
m = n // 4
m1 = m - 1
for i in range(n // 2):
if i != m:
for j in range(m):
x[i][j], x[n // 2 + i][j] = \
x[n // 2 + i][j], x[i][j]
for j in range(m1):
x[i][n - 1 - j], x[n // 2 + i][n - 1 -j] = \
x[n // 2 + i][n - 1 - j], x[i][n - 1 - j]
else:
for j in range(1, m + 1):
x[m][j], x[n // 2 + m][j] = \
x[n // 2 + m][j], x[m][j]
for j in range(m1):
x[m][n - 1 - j], x[n // 2 + m][n - 1 -j] = \
x[n // 2 + m][n - 1 -j], x[m][n - 1 - j]
matrix = magic(6)
print(matrix)
object Matrix {
def magic(n: Int) = {
val square = new Array[Array[Int]](n, n)
magic_o(square, n / 2)
exchange(square, n)
square
}
private def magic_o(square: Array[Array[Int]], n: Int) {
var row = 0
var column = n / 2
for(count <- 1 to n * n ) {
square(row)(column) = count
square(row+n)(column+n) = count + n*n;
square(row)(column+n) = count + 2*n*n;
square(row+n)(column) = count + 3*n*n;
if(count % n == 0) row += 1
else {
row = if(row == 0) n - 1 else row - 1
column = if(column == n-1) 0 else column + 1
}
}
}
private def exchange(x: Array[Array[Int]], n: Int) {
val m = n / 4
val m1 = m - 1
for(i <- 0 until n / 2) {
if(i != m) {
for(j <- 0 until m) swap(x, i, j, n/2+i, j)
for(j <- 0 until m1) swap(x, i, n-1-j, n/2+i, n-1-j)
}
else {
for(j <- 1 to m) swap(x, m, j, n/2+m, j)
for(j <- 0 until m1) swap(x, m, n-1-j, n/2+m, n-1-j)
}
}
}
private def swap(number: Array[Array[Int]],
i: Int, j: Int, k: Int, l: Int) {
val t = number(i)(j)
number(i)(j) = number(k)(l)
number(k)(l) = t
}
}
Matrix.magic(6).foreach(row => {
row.foreach(number => printf("%2d ", number))
println()
})
def magic(n)
square = Array.new(n) {
Array.new(n, 0)
}
magic_o(square, n / 2)
exchange(square, n)
square
end
def magic_o(square, n)
row = 0
column = n / 2
1.upto(n ** 2) { |count|
square[row][column] = count; # 填A
square[row + n][column + n] = count + n * n; # 填B
square[row][column + n] = count + 2 * n * n; # 填C
square[row + n][column] = count + 3 * n * n; # 填D
if count % n == 0
row += 1
else
row = (row == 0) ? n - 1 : row - 1
column = (column == n - 1) ? 0 : column + 1
end
}
end
def exchange(x, n)
m = n / 4
m1 = m - 1
(n / 2).times { |i|
if i != m
m.times { |j|
x[i][j], x[n / 2 + i][j] =
x[n / 2 + i][j], x[i][j]
}
m1.times { |j|
x[i][n - 1 - j], x[n / 2 + i][n - 1 -j] =
x[n / 2 + i][n - 1 - j], x[i][n - 1 - j]
}
else
1.upto(m) { |j|
x[m][j], x[n / 2 + m][j] =
x[n / 2 + m][j], x[m][j]
}
m1.times { |j|
x[m][n - 1 - j], x[n / 2 + m][n - 1 -j] =
x[n / 2 + m][n - 1 -j], x[m][n - 1 - j]
}
end
}
end
matrix = magic(6)
p matrix
function magic(n) {
let square = [];
for(let i = 0; i < n; i++) {
square.push([]);
}
magic_o(square, n/2);
exchange(square, n);
return square;
}
function magic_o(s, n) {
let row = 0;
let column = Math.floor(n / 2);
for(let count = 1; count <= n*n; count++) {
s[row][column] = count; // 填 A
s[row+n][column+n] = count + n*n; // 填 B
s[row][column+n] = count + 2*n*n; // 填 C
s[row+n][column] = count + 3*n*n; // 填 D
if(count % n == 0) {
row++;
}
else {
row = (row == 0) ? n - 1 : row - 1 ;
column = (column == n-1) ? 0 : column + 1;
}
}
}
function exchange(s, n) {
let m = Math.floor(n / 4);
let m1 = m - 1;
for(let i = 0; i < Math.floor(n / 2); i++) {
if(i != m) {
for(let j = 0; j < m; j++) // 處理規則 1
swap(s, i, j, n/2+i, j);
for(let j = 0; j < m1; j++) // 處理規則 2
swap(s, i, n-1-j, n/2+i, n-1-j);
}
else { // 處理規則 3
for(let j = 1; j <= m; j++)
swap(s, m, j, n/2+m, j);
for(let j = 0; j < m1; j++)
swap(s, m, n-1-j, n/2+m, n-1-j);
}
}
}
function swap(s, i, j, k, l) {
let t = s[i][j];
s[i][j] = s[k][l];
s[k][l] = t;
}
matrix = magic(6)
console.log(matrix)
slice :: Int -> Int -> [a] -> [a]
slice start stop xs = take (stop - start) (drop start xs)
updated i j v mx =
let
row = mx !! i
updatedRow = (slice 0 j row) ++ [v] ++ (slice (j + 1) (length row) row)
before = slice 0 i mx
after = slice (i + 1) (length mx) mx
in before ++ [updatedRow] ++ after
swapped i j k l mx =
updated k l (mx !! i !! j) $ updated i j (mx !! k !! l) mx
exchanged n mx =
let m = n `div` 4
m1 = m - 1
in _exchanged (n `div` 2) m m1 n 0 mx
where
_exchanged stop m m1 n i mx =
if i == stop then mx
else
if i /= m then _exchanged stop m m1 n (i + 1) $ rule2 m1 i n $ rule1 m i n mx
else _exchanged stop m m1 n (i + 1) $ rule32 m1 m n $ rule31 m n mx
rule1 m i n mx =
_forSwapped m i 0 n mx
where
_forSwapped stop i j n mx =
if j == stop then mx
else _forSwapped stop i (j + 1) n $ swapped i j (n `div` 2 + i) j mx
rule2 m1 i n mx =
_forSwapped m1 i 0 n mx
where
_forSwapped stop i j n mx =
if j == stop then mx
else _forSwapped stop i (j + 1) n $ swapped i (n-1-j) (n `div` 2 + i) (n-1-j) mx
rule31 m n mx =
_forSwapped (m + 1) m 1 n mx
where
_forSwapped stop m j n mx =
if j == stop then mx
else _forSwapped stop m (j + 1) n $ swapped m j (n `div` 2 + m) j mx
rule32 m1 m n mx =
_forSwapped m1 m 0 n mx
where
_forSwapped stop m j n mx =
if j == stop then mx
else _forSwapped stop m (j + 1) n $ swapped m (n-1-j) (n `div` 2 + m) (n-1-j) mx
magic0 n mx = _magic0 0 (n `div` 2) n 1 mx
where
_magic0 row column n counter mx =
let nn = n * n
in
if counter == nn + 1 then mx
else
let
nmx = updated (row + n) column (counter + 3 * nn) $
updated row (column + n) (counter + 2 * nn) $
updated (row + n) (column + n) (counter + nn) $
updated row column counter mx
(nr, nc) = _nrc counter n row column
in _magic0 nr nc n (counter + 1) nmx
where
_nrc counter n row column =
if counter `mod` n == 0 then (row + 1, column)
else (if row == 0 then n - 1 else row - 1, if column == n - 1 then 0 else column + 1)
magic n =
let matrix = replicate n $ replicate n 0
in exchanged n $ magic0 (n `div` 2) matrix
main = print $ magic 6