奇数幻方:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 55;
int a[maxn][maxn];
int main()
{
int n;
scanf("%d",&n);
int val = 1, pos = (n + 1) / 2;
for (int i = 1; i <= (n + 1) / 2; i++)
{
for (int j = 1; j <= i * 2 - 1; j++)
{
a[i][pos + j - 1] = val; val += 2;
}
pos -= 1;
}
pos = (n + 1) / 2;
for (int i = n; i > (n + 1) / 2; i--)
{
for (int j = 1; j <= (n - i + 1) * 2 - 1; j++)
{
a[i][pos + j - 1] = val; val += 2;
}
pos -= 1;
}
val = 2;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (a[i][j] == 0)
{
a[i][j] = val; val += 2;
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
printf("%d%c", a[i][j], j == n ? '\n' : ' ');
}
}
return 0;
}
普通幻方:
/*
幻方的计算:
计算任意阶数幻方的各行、各列、各条对角线上所有数的和的公式为:sum=n*(n^2+1)/2 n为阶数
幻方分为奇阶幻方和偶阶幻方
一、当n为奇数时称为奇阶幻方
1、Merzirac法生成奇阶幻方
在第一行居中的方格内放1,依次向右上方填入2、3、4…,如果右上方已有数字,则向下移一格继续填写。
2、loubere法生成奇阶幻方
在居中的方格向上一格内放1,依次向右上方填入2、3、4…,如果右上方已有数字,则向上移两格继续填写
3、horse法生成奇阶幻方
(1)对于所有的奇阶幻方,在第一行居中的方格内放1,向左走1步,下走2步以跳马步,依次填入2、3、4…,
若出到方阵下方,把该数字填到本该填数所在列上方相应的格;
若出到方阵右方,把该数字填到本该填数所在行的左方相应的格;
如果落步格已有数字, 则向下移一格继续填写。
(2)n阶奇阶幻方,若n为不是3的倍数,那么在任意一格内放1,向左走1步,下走2步以跳马步,依次填入2、3、4…,
若出到方阵下方,把该数字填到本该填数所在列上方相应的格;
若出到方阵右方,把该数字填到本该填数所在行的左方相应的格;
如果落步格已有数字, 则向上移一格继续填写
二、当n为偶数时称为偶阶幻方;
偶阶幻方分为双偶幻方和单偶幻方。
当n可以被4整除时,我们称该偶阶幻方为双偶幻方,如8阶、12阶、16阶等;
当n不可被4整除时,我们称该偶阶幻方为单偶幻方,如6阶、10阶、14阶等
1、双偶数幻方
(1)Spring法生成双偶幻方
方法:顺序填数,以中心点对称互换数字。
第一步,先令a(i,j)=(i-1)*n+j,
即第一行从左到可分别填写1、2、3、……、n;
即第二行从左到可分别填写n+1、n+2、n+3、……、2n;…………n^2
第二步,进行对称交换。
2、单偶数幻方
当n为非4倍数的偶数(即4n+2形)时:首先把大方阵分解为4个奇数(2m+1阶)子方阵。
按上述奇数阶幻方给分解的4个子方阵对应赋值
上左子阵最小(i),下右子阵次小(i+v),下左子阵最大(i+3v),上右子阵次大(i+2v)
即4个子方阵对应元素相差v,其中v=n*n/4
四个子矩阵由小到大排列方式为
① ③
④ ②
然后作相应的元素交换:a(i,j)与a(i+k,j)在同一列做对应交换
(j<t或j>n-t+2),a(t-1,0)与a(t+k-1,0);a(t-1,t-1)与a(t+k-1,t-1)两对元素交换
其中k=n/2,t=(n+2)/4 上述交换使每行每列与两对角线上元素之和相等。
*/
#include <stdio.h>
#include <math.h>
int a[256][256];
int sum;
int check(int n);
void oddMagic(int n);
void doubleEvenMagic(int n);
void singleEvenMagic(int n);
int myabs(int x)
{
return x>=0? x:-x;
}
int main()
{
int i,j,k,n;
scanf("%d",&n);
sum = (n*(n*n+1))/2;
if(n%2==1)//奇数幻方
{
oddMagic(n);
k=n;
}else if(n%4==2)//单偶数幻方
{
singleEvenMagic(n);
}else if(n%4==0)//双偶数幻方
{
doubleEvenMagic(n);
}
if(check(n)==1)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%d ",a[i][j]);
printf("\n");
}
}
return 0;
}
int check(int n)
{
int i,j,sum1=0,sum2=0;
/*
测试每一行的和是否为sum
a[0][0]+a[0][1]+a[0][2]+...第一行
*/
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
sum1+=a[i][j];
if(sum1!=sum)
return 0;
sum1=0;
}
/*
测试每一列的和是否为sum
a[0][0]+a[1][0]+a[2][0]+..第一列
*/
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
sum1+=a[j][i];
if(sum1!=sum)
return 0;
sum1=0;
}
/*
测试对角线上的和是否为sum
a[0][0]+a[1][1]+a[2][2]+...+a[n][n]从左上角到右下角的各
a[0][n-1]+a[1][n-2]+a[2][n-3]+...+a[n-1][0]从右上角到左下角的和
*/
for(sum1=0,i=0;i<n;i++)
{
sum1+=a[i][i];
sum2+=a[i][n-i-1];
}
if(sum1!=sum)
return 0;
if(sum2!=sum)
return 0;
else return 1;
}
void oddMagic(int n)
{
int x=0,y,m;
y=n/2;
for(m=1;m<=n*n;m++)
{
a[x][y]=m;
if(m%n!=0)
{
//后面的每一个数存放的行比前一个数的行数减1,列数加1
x--;
y++;
//如果超界要从另一面进来
if(x<0)
x+=n;
if(y==n)
y=n-y;
}else
{
//如果右上角已经有数字了,则后一个数字在当前数字下
x++;
if(x==n)
x=x-n;
}
}
}
void doubleEvenMagic(int n)
{
int x=1,i,j,k;
//从左到右,从上到下,赋初值1,2,3...n^2;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
a[i][j]=x++;
/*
将幻方等分成m*m个4阶幻方,将各4阶幻方中对角线上(或非对角线上)
的方格内数字与n阶幻方内以中心点为对称点的对角数字进行交换。
*/
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
/*
满足条件时,i=0或4的倍数,所以j=i,或者i-j的绝对值是4的倍数
1、从左上角到右下角对角线的值,a[0][0],a[1][1]...a[n][n]
2、以a[0][4]为起点,k循环时向右下角的四个数a[1][5],a[2][6],a[3][7]
3、以a[4][0]为起点,k循环时向右下角的四个数a[5][1],a[6][2],a[7][3]
*/
if(i%4==0 && myabs(i-j)%4==0)
for(k=0;k<4;k++)
a[i+k][j+k]=n*n-a[i+k][j+k]+1;
else if(i%4==3 && (i+j)%4==3)//右上角到左下角的
for(k=0;k<4;k++)
a[i-k][j+k]=n*n-a[i-k][j+k]+1;
}
}
void singleEvenMagic(int n)
{
int k,i,j,p,t;
k=n/2;
oddMagic(k);
/*
先赋初值
上左子阵最小(i),下右子阵次小(i+v),下左子阵最大(i+3v),上右子阵次大(i+2v)
即4个子方阵对应元素相差v,其中v=n*n/4
*/
for(i=0;i<k;i++)
for(j=0;j<k;j++)
{
a[i][j+k]=a[i][j]+2*k*k;
a[i+k][j]=a[i][j]+3*k*k;
a[i+k][j+k]=a[i][j]+k*k;
}
t=(n-2)/4;
for(i=0;i<k;i++)
for(j=0;j<k;j++)
{
if((j<t)&&(i<t))
{
p=a[i][j];
a[i][j]=a[i+k][j];
a[i+k][j]=p;
}
if((j<t)&&(i>k-t-1))
{
p=a[i][j];
a[i][j]=a[i+k][j];
a[i+k][j]=p;
}
if((i>=t&&i<=k-t-1)&&(j>=t&&j<t*2))
{
p=a[i][j];
a[i][j]=a[i+k][j];
a[i+k][j]=p;
}
if(j>1&&j<=t)
{
p=a[i][j+k];
a[i][j+k]=a[i+k][j+k];
a[i+k][j+k]=p;
}
}
}