2(2N+1) 魔方陣

December 12, 2021

2(2N+1) 魔方陣的維度整體來看是偶數,然而可以分解為奇數乘以偶數,例如 6 x 6 方陣,其中 6 = 2 X 3,也稱這種方陣為單偶數(oddly-even)方陣,各行、各列與各對角線的和必須相同。

解法思路

首先令 n = 2 * (2 * m + 1),並將整個方陣看靈數個奇數方陣的組合:

2(2N+1) 魔方陣

先依序將 A、B、C、D 四個位置,依奇數魔方陣規則填入數字,填完後方陣中各行和就相同了,但列與對角線則否,此時必須在 A-D 與 C- B 之間調換,規則如下:

  1. 將 A 中每列(中間列除外)頭 m 個元素,與 D 中對應位置元素調換。
  2. 將 A 的中央列、中央那一格向左取 m 格,並與 D 中對應位置對調。
  3. 將 C 中每列的倒數 m - 1 個元素,與 B 中對應元素對調。

以 6 x 6 方陣為例,先分解為奇數方陣,並填入數字:

2(2N+1) 魔方陣

接下來進行互換,互換的元素以不同顏色標示:

2(2N+1) 魔方陣

由於 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

分享到 LinkedIn 分享到 Facebook 分享到 Twitter