魔方陣又叫幻方(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");
}
}