魔方陣的實現(C語言)

魔方陣又叫幻方(Magic Square),是一種將數字安排在正方形格子中,使每行、列和對角線上的數字和都相等的方法。幻方也是一種中國傳統遊戲。舊時在官府、學堂多見。它是將從一到若干個數的自然數排成縱橫各爲若干個數的正方形,使在同一行、同一列和同一對角線上的幾個數的和都相等。
對平面幻方的構造,分爲三種情況:N爲奇數、N爲4的倍數、N爲其它偶數(4n+2的形式)
1、 N 爲奇數時,最簡單:
⑴ 將1放在第一行中間一列;
⑵ 從2開始直到n×n止各數依次按下列規則存放:
按 45°方向行走,如向右上
每一個數存放的行比前一個數的行數減1,列數加1
⑶ 如果行列範圍超出矩陣範圍,則迴繞。
例如1在第1行,則2應放在最下一行,列數同樣加1;
⑷ 如果按上面規則確定的位置上已有數,或上一個數是第1行第n列時,
則把下一個數放在上一個數的下面。
2、 N爲4的倍數時
採用對稱元素交換法。
首先把數1到n×n按從上至下,從左到右順序填入矩陣
然後將方陣的所有4×4子方陣中的兩對角線上位置的數關於方陣中心作對
稱交換,即a(i,j)與a(n+1-i,n+1-j)交換,所有其它位置上的數不變。
(或者將對角線不變,其它位置對稱交換也可)
**以上方法只適合於n=4時**
3、 N 爲其它偶數時
當n爲非4倍數的偶數(即4n+2形)時:首先把大方陣分解爲4個奇數(2m+1階)子方陣。
按上述奇數階幻方給分解的4個子方陣對應賦值
由小到大依次爲上左子陣(i),下右子(i+v),上右子陣(i+2v),下左子陣(i+3v),
即4個子方陣對應元素相差v,其中v=n*n/4
四個子矩陣由小到大排列方式爲 ① ③
④ ②
然後作相應的元素交換:a(i,j)與a(i+u,j)在同一列做對應交換(j<t或j>n-t+2),
a(t-1,0)與a(t+u-1,0);a(t-1,t-1)與a(t+u-1,t-1)兩對元素交換

其中u=n/2,t=(n+2)/4 上述交換使行列及對角線上元素之和相等。


C語言代碼如下

#include <stdio.h>
#include <stdlib.h>
void swap(int *i,int *j)
{
    int t;
    t=*i;
    *i=*j;
    *j=t;
}
void n_qtosmfz(int k)
{
    int a,x,y,i,j,n;
    n=k/2;
    int f[n][n],g[n][n],h[n][n],l[n][n];
    f[(n+1)/2-1][0]=1;   //左上
    x=(n+1)/2-1;
    y=0;
    for(a=2; a<=n*n; a++)
    {
        if((a-1)%n==0)
        {
            f[x][y+1]=a;
            y++;
        }
        else
        {
            if(x+1==n)
                x=0;
            else
                x++;
            if(y-1<0)
                y=n-1;
            else
                y--;
            f[x][y]=a;
        }
    }

    g[(n+1)/2-1][0]=1+k*k/2;   //右上
    x=(n+1)/2-1;
    y=0;
    for(a=2+k*k/2; a<=n*n+k*k/2; a++)
    {
        if((a-1)%n==0)
        {
            g[x][y+1]=a;
            y++;
        }
        else
        {
            if(x+1==n)
                x=0;
            else
                x++;
            if(y-1<0)
                y=n-1;
            else
                y--;
            g[x][y]=a;
        }
    }
    h[(n+1)/2-1][0]=1+3*k*k/4;   //左下
    x=(n+1)/2-1;
    y=0;
    for(a=2+3*k*k/4; a<=n*n+3*k*k/4; a++)
    {
        if((a-1)%n==0)
        {
            h[x][y+1]=a;
            y++;
        }
        else
        {
            if(x+1==n)
                x=0;
            else
                x++;
            if(y-1<0)
                y=n-1;
            else
                y--;
            h[x][y]=a;
        }
    }
    l[(n+1)/2-1][0]=1+k*k/4;   //右下
    x=(n+1)/2-1;
    y=0;
    for(a=2+k*k/4; a<=n*n+k*k/4; a++)
    {
        if((a-1)%n==0)
        {
            l[x][y+1]=a;
            y++;
        }
        else
        {
            if(x+1==n)
                x=0;
            else
                x++;
            if(y-1<0)
                y=n-1;
            else
                y--;
            l[x][y]=a;
        }
    }
    int m=(k-2)/4;
    for(i=m+2; i<k/2; i++)             //交換右半兩個小方陣中大於k+2的列。
        for(j=0; j<k/2; j++)
            swap(&g[i][j],&l[i][j]);

    swap(&f[m][m],&h[m][m]);
    swap(&f[0][m],&h[0][m]);

    for(i=0; i<m; i++)
        for(j=0; j<k/2; j++)
            swap(&f[i][j],&h[i][j]);
    for(j=0; j<n; j++)
    {
        {
            for(i=0; i<n; i++)
                printf("%-2d  ",f[i][j]);
            for(i=0; i<n; i++)
                printf("%-2d  ",g[i][j]);
        }
        printf("\n\n");
    }
    for(j=0; j<n; j++)
    {
        {
            for(i=0; i<n; i++)
                printf("%-2d  ",h[i][j]);
            for(i=0; i<n; i++)
                printf("%-2d  ",l[i][j]);
        }
        printf("\n\n");
    }
}
void n_4kmfz(int n)
{
    int i=1,j=0,k;
    int a[n][n];
    a[0][0]=1;
    while(i*j<=(n-1)*(n-1))   //首先把數1到n×n按從上至下,從左到右順序填入矩陣
    {
        a[i][j]=a[i-1][j]+1;
        i++;
        if(i==n&&j!=n-1)
        {
            i=1;
            j++;
            a[0][j]=a[n-1][j-1]+1;
        }
    }
    k=n/4;
    for(i=0; i<k; i++)               /*然後將方陣的所有4×4子方陣中的兩對角線上位置的數關於方陣中心作對
                                      稱交換,即a(i,j)與a(n+1-i,n+1-j)交換,所有其它位置上的數不變。*/
        for(j=0; j<k; j++)
        {
            swap(&a[4*i][4*j],&a[n-1-4*i][n-1-4*j]);
            swap(&a[4*i+1][4*j+1],&a[n-1-4*i-1][n-1-4*j-1]);
            swap(&a[4*i][4*j+3],&a[n-1-4*i][n-1-4*j-3]);
            swap(&a[4*i+1][4*j+2],&a[n-1-4*i-1][n-1-4*j-2]);
        }
    for(i=0; i<n; i++)
    {
        for(j=0; j<n; j++)
            printf("%-4d ",a[i][j]);
        printf("\n\n");
    }
}
void jsjmfz(int n)
{
    int a,x,y,i,j;
    int f[n][n];
    f[(n+1)/2-1][0]=1;
    x=(n+1)/2-1;
    y=0;
    for(a=2; a<=n*n; a++)
    {
        if((a-1)%n==0)
        {
            f[x][y+1]=a;
            y++;
        }
        else
        {
            if(x+1==n)
                x=0;
            else
                x++;
            if(y-1<0)
                y=n-1;
            else
                y--;
            f[x][y]=a;
        }
    }
    for(j=0; j<n; j++)
    {
        for(i=0; i<n; i++)
        {
            printf("%-2d  ",f[i][j]);         //控制格式,考慮%-*d格式
        }
        printf("\n\n");                         //換行考慮自定義函數循環
    }
}
int main()
{
    int n=1;
    while (n!=-1)
    {
        printf("請輸入魔方陣階數(請輸入正整數,輸入-1結束程序):\n");
        scanf("%d",&n);
        printf("--------------------------------------\n");
        if(n%2!=0)
            jsjmfz(n);
        else
        {
            if(n==2)
                printf("該階數魔方陣不存在\n");
            else if (n%4==0)
                n_4kmfz(n);
            else
                n_qtosmfz(n);
        }
        printf("--------------------------------------\n");
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章