幻方算法 C語言描述


幻方算法的所有情況描述及C語言表示 2019-03-30

討論幻方前,先討論一下動態申請數組大小

眾所周知 在C語言中必須指定數組的大小 否則會報錯。如果你不知道你要申請多大的數組怎么辦?初始化一個非常大的數組?顯然浪費空間。。

頭文件#include<stdlib.h> 為我們提供了malloc函數 即動態內存分配函數 我們可以用它來為我們分配我們想要的數組大小

你想分配一個自己鍵盤輸入大小的數組 就用malloc函數來實現(以下代碼都用偽代碼表示)

本題的申請數組就將用到這個方法

1.int *arr;//聲明一個指針變量

scanf("%d",&n);

a=(int *)malloc(sizeof(int)*n);//這樣就新建了一個長度為n的一維數組

2.int **arr;//聲明一個二級指針 即指向指針的指針

    scanf("%d",&n);
    arr = (int **)malloc(sizeof(int*)*n);//申請一個n*n的二維數組
    for (i = 0;i < n;i++)
    arr[i] = (int *)malloc(sizeof(int)*n);

 

 

一、幻方按照階數可成了三類,奇數階幻方雙偶階幻方(n%4==0)、單偶階幻方(n-2%4==0)

奇數階幻方(勞伯法)

奇數階幻方最經典的填法是羅伯法。填寫的方法是:

 

把1(或最小的數)放在第一行正中;按以下規律排列剩下的(n×n-1)個數:
1每一個數放在前一個數的右上一格;

 

(2如果這個數所要放的格已經超出了頂行那么就把它放在底行,仍然要放在右一列;

 

 

 

3)如果這個數所要放的格已經超出了最右列那么就把它放在最左列,仍然要放在上一行;

 

 

 

4如果這個數所要放的格已經超出了頂行且超出了最右列,那么就把它放在底行且最左列;

 

 

 

5如果這個數所要放的格已經有數填入,那么就把它放在前一個數的下一行同一列的格內。

 

 

 

例,用該填法獲得的5階幻方:

 

二、雙偶數階幻方(海爾法)

所謂雙偶階幻方就是當n可以被4整除時的偶階幻方,即4K階幻方。在說解法之前我們先說明一個“互補數”定義:就是在n階幻方中,如果兩個數的和等於幻方中最大的數與1的和(即n×n+1),我們稱它們為一對互補數。如在三階幻方中,每一對和為10的數,是一對互補數 ;在四階幻方中,每一對和為17的數,是一對互補數。

雙偶數階幻方最經典的填法是海爾法。填寫的方法是:

8階幻方為例:
1先把數字按順序填。然后,按4×4把它分割成4塊(如圖)

2每個小方陣對角線上的數字(如左上角小方陣部分),換成和它互補的數。

三、單偶數階幻方(斯特拉茲法)

所謂單偶階幻方就是當n不可以被4整除時的偶階幻方,即4K+2階幻方。如(n=61014……)的幻方。

 

單偶數階幻方最經典的填法是斯特拉茲法。填寫的方法是:

10階幻方為例。這時,k=2
1)把魔方陣分為ABCD四個象限,這樣每一個象限肯定是奇數階。用羅伯法,依次在A象限,D象限,B象限,C象限按奇數階幻方的填法填數。

 

 

2)在A象限的中間行、中間格開始,按自左向右的方向,標出k格。A象限的其它行則標出最左邊的k格。將這些格,和C象限相對位置上的數互換位置。

3)在B象限所有行的中間格,自右向左,標出k1格。(注:6階幻方由於k1=0,所以不用再作BD象限的數據交換),將這些格,和D象限相對位置上的數互換位置。

C語言代碼如下(才疏學淺代碼盡力了)

#include<stdio.h>
#include<stdlib.h>


int laobo(int n,int **arr,int num)
//勞伯法 用於計算奇數階的情況
{
    int i, j, k;
    i = 0;
    j = n / 2;
    for (k = num;k <=num+n*n-1;k++)
//num代表第一個數 之所以引入這個num是因為后面有個函數需要
//一般來說  是以1開始
    {
        arr[i][j] = k;
        if (arr[(i - 1 + n) % n][(j + 1 + n) % n] == 0)
        {
            i = (i - 1 + n) % n;
            j = (j + 1 + n) % n;
        }
        else
        {
            i= (i + 1 + n) % n;
        }
    }
    return 0;
}
int Init(int n, int **arr)
{
    //初始化數組 形成 1 2 3 4
    //                5 6 7 8.....這類
    //為海爾法做好基礎
    int i, j, num;
    num = 1;
    for (i = 0;i < n;i++)
    {
        for (j = 0;j < n;j++)
        {
            arr[i][j] = num++;
        }
    }
    return 0;
}
int haier(int n, int **arr)//被4整除時用該函數
{
    int i, j, complement, deg;//complement表示互補數 即n*n+1
    //deg表示n/4 因為要分成4*4的
    complement = n*n + 1;
    deg = n / 4;
    for (i = 0;i < deg;i++)
    {
        for (j = 0;j < deg;j++)
        {
            arr[i * 4 + 0][j * 4 + 0] = complement - arr[i * 4 + 0][j * 4 + 0];
            arr[i * 4 + 0][j * 4 + 3] = complement - arr[i * 4 + 0][j * 4 + 3];
            arr[i * 4 + 1][j * 4 + 1] = complement - arr[i * 4 + 1][j * 4 + 1];
            arr[i * 4 + 1][j * 4 + 2] = complement - arr[i * 4 + 1][j * 4 + 2];
            arr[i * 4 + 2][j * 4 + 1] = complement - arr[i * 4 + 2][j * 4 + 1];
            arr[i * 4 + 2][j * 4 + 2] = complement - arr[i * 4 + 2][j * 4 + 2];
            arr[i * 4 + 3][j * 4 + 0] = complement - arr[i * 4 + 3][j * 4 + 0];
            arr[i * 4 + 3][j * 4 + 3] = complement - arr[i * 4 + 3][j * 4 + 3];
        }
    }
    return 0;
}
int late(int n, int **arr)
{
    int deg;
    int k;
    int temp;
    int i, j;
    deg = n / 2;
    //laobo(deg,n, arr, x, y, num);//用laobo法填充A象限
    //laobo(deg,n, arr, x+deg, y+deg, num+deg*deg);//用laobo法填充D象限
    //laobo(deg,n, arr, x+deg, y, num+2*deg*deg);//用laobo法填充B象限
    //laobo(deg,n, arr, x, y+deg, num+3*deg*deg);//C
    int **a;
    a = (int **)malloc(sizeof(int*)*deg);
    for (int m = 0;m < deg;m++)
        a[m] = (int *)malloc(sizeof(int)*deg);
    for (i = 0;i < deg;i++)
        for (j = 0;j < deg;j++)
            a[i][j] = 0;
    laobo(deg, a, 1);

    for (i = 0;i < deg;i++)//A象限賦值
        for (j = 0;j < deg;j++)
        {
            arr[i][j] = a[i][j];
        }
    for (i = 0;i < deg;i++)
        for (j = 0;j < deg;j++)
            a[i][j] = 0;
    laobo(deg, a, 1+deg*deg);
    for (i = 0;i < deg;i++)//D象限賦值
        for (j = 0;j < deg;j++)
        {
            arr[i+deg][j+deg] = a[i][j];
        }
    for (i = 0;i < deg;i++)
        for (j = 0;j < deg;j++)
            a[i][j] = 0;
    laobo(deg, a, 1 + 2*deg*deg);
    for (i = 0;i < deg;i++)//B象限賦值
        for (j = 0;j < deg;j++)
        {
            arr[i][j + deg] = a[i][j];
        }
    for (i = 0;i < deg;i++)
        for (j = 0;j < deg;j++)
            a[i][j] = 0;
    laobo(deg, a, 1 + 3*deg*deg);
    for (i = 0;i < deg;i++)//C象限賦值
        for (j = 0;j < deg;j++)
        {
            arr[i + deg][j] = a[i][j];
        }

    k = (n - 2) / 4;

    for (i = 0;i < deg;i++)//實現了AC象限前k個數的交換
    {
        for (j = 0;j < k;j++)
        {
            temp = arr[i][j];
            arr[i][j] = arr[i + deg][j];
            arr[i + deg][j] = temp;
        }
    }
    
    for (j = 0;j < k;j++)//因為A象限中間行是從中間格開始換的
        //所以我們要將前面替換了的前k格給替換回來
    {
        temp = arr[deg / 2][j];
        arr[deg / 2][j] = arr[deg / 2 + deg][j];
        arr[deg / 2 + deg][j] = temp;
    }
    //替換中間格開始的k個
    for (j = deg/2;j <((deg/2) + k);j++)
    {
        temp = arr[deg / 2][j];
        arr[deg / 2][j] = arr[deg / 2 + deg][j];
        arr[deg / 2 + deg][j] = temp;
    }
    if (k != 0)
    {
        for (i = 0;i < deg;i++)
            for (j = deg + deg / 2;j < ((deg + deg / 2) + k - 1);j++)
        {
            temp = arr[i][j];
            arr[i][j] = arr[i + deg][j];
            arr[i + deg][j] = temp;
        }
    }

    free(a);
    return 0;
}
int main()
{
    int **arr;//二級指針動態申請二維數組
    int n;
    int i, j;
    printf("請輸入你想打印幾階幻方:");
    scanf("%d",&n);
    arr = (int **)malloc(sizeof(int*)*n);//申請一個n*n的二維數組
    for (i = 0;i < n;i++)
    arr[i] = (int *)malloc(sizeof(int)*n);
    for (i = 0;i < n;i++)
        for (j = 0;j < n;j++)
            arr[i][j] = 0;
    if (n % 2 != 0)
    {
        laobo(n, arr,1);
    }
    else if (n % 4 == 0)
    {
        Init(n, arr);
        haier(n, arr);
    }
    else
    {
        
        late(n, arr);
    }
    for (i = 0;i < n;i++)
    {
        for (j = 0;j < n;j++)
        {
            printf("%4d", arr[i][j]);
        }
        printf("\n");
    }

    free(arr);
    return 0;
}

emmm 看不懂私信我吧。。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM