神奇的魔方陣--(MagicSquare)(1)

Wz_qq_2***6發表於2021-04-10

篇文章只對奇數階以及偶數階中階數n = 4K的魔方陣進行討論.下面就讓我們進入正題:

 

1 :魔方陣的相關資訊:(百度百科)

https://baike.baidu.com/item/%E9%AD%94%E6%96%B9%E9%98%B5/10973743?fr=aladdin

 

2 :奇數階和偶數階魔方陣的排列規律.(源自百度百科)  (可跳至第三部分)

    2.1 :奇數階魔方陣的排列規律如下:
  ⑴ :將1放在第一行中間一列;
  ⑵ :從2開始直到n×n止各數依次按下列規則存放;每一個數存放的行比前一個數的行數減1,列數加1(例如上面的三階魔方陣,5在4的上一行後一列;
  ⑶ :如果上一個數的行數為1,則下一個數的行數為n(指最下一行);例如1在第一行,則2應放在最下一行,列數同樣加1;
  ⑷ :當上一個數的列數為n時,下一個數的列數應為1,行數減去1。例如2在第3行最後一列,則3應放在第二行第一列;
  ⑸ :如果按上面規則確定的位置上已有數,或上一個數是第一行第n列時,則把下一個數放在上一個數的下面。例如按上面的規定,4應該放在第1行第2列,
       但該位置已經被佔據,所以4就放在3的下面。
 
    2.2 :階數為n = 4K 的魔方陣的排列規律如下:
  (1) :先將整個方陣劃分成k*k個4階方陣,然後在每個4階方陣的對角線上做記號;
  (2) :由左而右、由上而下,遇到沒有記號的位置才填數字,但不管是否填入數字,每移動一格數字都要加1;
  (3) :自右下角開始,由右而左、由下而上,遇到沒有數字的位置就填入數字,但每移動一格數字都要加1。
 
3 :排列規律的解讀,程式碼實現以及實驗結果( ar 二維陣列 ,ROW ==行,  COL ==  列)
 3.1 :奇數階魔方陣(n = 2*K + 1)
 奇數階魔方陣的排列規律主要有以下三點:
   3.1.1) : 數字1的位置是確定的,擺放在第一行中間的位置,即:  ar[0][COL/2] == 1;
 
   3.1.2)(重點)  :假設當前擺放的數行列下標為 [preRow][preCol] , 則下一個數的擺放的位置的下標應為[preRow - 1] [preCol + 1] ,注意在這裡(preRow - 1)
       以及(preCol + 1)的值都有可能越界. 因此,需要對變化後的值進行操作.我們以ROW=COL=3為例,假設上一個值的下標為 [0][3] ,
          那麼下一個值的下標應為[2][1] ,他們與(preRow - 1)以及(preCol + 1)
       即 [0 - 1][3 + 1]的關係,為[(-1 + 3)%3] [(3+1+3)%3], 即[(preRow - 1+ ROW)%ROW][(preCol + 1+ COL)%COL].
       圖示:
 
         ,
      2的擺放位置的下標應為[(0 -1 + 3)%3][(1+1)%3] == [2][2] ,
      即:  
 
   3.1.3) : 若將要擺放的位置已有值存在,則將該值排放在上一個值的下一行.
      例如:以三階魔方陣為例: 按照相應的規則擺放1,2,3
                       ,
      要擺放4的位置的下標通過計算可以得出是[0][1],但是該位置已有數值1,因此4要擺放在3的下一行,即[preRow - 1][preCol],
      同時用3.1.2的方法對[preRow-1]進行 防越界處理:   [(preRow - 1 + ROW)%ROW][preCol]. 
    程式碼如下:
#include<assert.h>
#include<stdio.h>
void Magic_Square_1()
{
#define ROW 3
#define COL ROW   //   等價於 #define COL 3
    assert(ROW % 2 != 0);
    if (ROW % 2 == 0)//ROW & ! == 1 判斷是否為奇數  &(只有全為1,才為1)
    {
        return;
    }
    int preRow = 0;  //記錄上一個數的行座標
    int preCol = 0;  //記錄上一個數的列座標
    int ar[ROW][COL] = {};
    ar[0][COL / 2] = 1;  //先放1
    preRow = 0;
    preCol = COL / 2; 
    for (int i = 2; i <= ROW * COL; i++)//1已經放入所以從2開始進行
    {
        if (ar[(preRow - 1 + ROW) % ROW][(preCol + 1) % COL] == 0)
            //判斷上一個數的上一行下一列是否有值若沒有則放入當前的i
        {
            preRow = (preRow - 1 + ROW) % ROW;
            preCol = (preCol + 1) % COL;
        }
        else
        { // 若有則i放在上一個數的下一行.
            preRow = (preRow + 1) % ROW;
        }
        ar[preRow][preCol] = i;
    }
    for (int i = 0; i < ROW; i++)//列印
    {
        for (int j = 0; j < COL; j++)
        {
            printf("%3d", ar[i][j]);
        }
        printf("\n");
    }
#undef ROW     //取消定義
#undef COL
}
int main()
{
  Maagic_Square_1();
  return 0;
}

   執行結果:

  

 
3.2 :偶數階魔方陣( n = 4*K )
 偶數階魔方陣的排列規律主要有以下兩點:(以8階為例)
   3.2.1) : 先將 1 - ROW*COL 的值按從上到下,從左到右的順序依次填入.接著將魔方陣分成k*k (在該例 k = 2)個4階魔方陣,並將4階魔方陣的對角線的數值取出(如下圖帶顏色部分的數值).
                   

 

   3.2.2) : 將取出來的值按照從大到小的順序(或從小到大的順序)排好,從二維陣列的[0][0]下標開始(從二維陣列[ROW - 1][COL - 1]的位置開始) 依次填入到陣列中空白的位置.

      (重點)排列n= 4*k 階的魔方陣的關鍵是取出各個四階魔方陣的對角線的元素.我們可以發現:所有在對角線的元素的行列下標只差都滿足一定的規律:

    即 |row - col|(絕對值) % 4 == 0 (對應圖中黃色部分)或者(row + col)%4 == 3(對應圖中紅色部分) .同時我們可以定義一個陣列br[ROW*ROW/2],

    在第一步填入資料時對其行列下標進行判斷,若滿足對角線元素下標的特點,直接將數值存放到br中,同時對二維陣列相應的位置賦零值.

    這樣br 中的數就是從小到大排列的,只需要在第二步時從二維陣列ar 的ar[ROW - 1][COL - 1]的位置開始,

         依次將陣列br中的值填入到陣列中空白的位置.

                  

 

       程式碼如下:

#include<stdio.h>
#include<assert.h>
void Magic_Square_4K()
{
#define ROW 8
#define COL ROW
    int ar[ROW][COL] = {};
    int br[ROW*ROW/2] = {};//用來儲存4階方陣對角線元素.
    int num = 1;//從1開始填入
    int k = 0;//陣列br下標.
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
        if((i-j)%4==3||(i-j)%4==0|| (j - i) % 4 == 3 || (j - i) % 4 == 0)
        {//先控制對角線元素為零,並將應該填在對角線的這些數記錄到br中.
            br[k] = num;
            k += 1;
            ar[i][j] = 0;
        }
        else
        {
            ar[i][j] = num;
        }
        num++;
        }
    }
    int tag = 0;
    for (int i = ROW - 1; i >= 0; i--)//將br中的數按照順序,從ar[ROW-1][COl-1]開始對ar中為零的元素賦值.
    {
        for (int j = COL - 1; j >= 0; j--)
        {
            if (ar[i][j] == 0)
            {
                ar[i][j] = br[tag];
                tag += 1;
            }
        }
    }

    for (int i = 0; i < ROW; i++)//列印
    {
        for (int j = 0; j < COL; j++)
        {
            printf("%4d", ar[i][j]);
        }
        printf("\n");
    }
#undef ROW
#undef COL
}
int main()
{
    Magic_Square_4K();
    return 0;
}

     執行結果:

   

 

 

未完待續...

 

相關文章