/*幻方的计算:计算任意阶数幻方的各行、各列、各条对角线上所有数的和的公式为: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> #include <algorithm>
#include <iostream> int a[256][256]; int sum; int check(int n); void oddMagic(int n); void doubleEvenMagic(int n); void singleEvenMagic(int n); 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%c",a[i][j], j == n - 1 ? '\n' : ' ');}}return 0; } int check(int n) {int i,j,sum1=0,sum2=0;//printf("Checking......................\n");/*测试每一行的和是否为suma[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;}/*测试每一列的和是否为suma[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;}/*测试对角线上的和是否为suma[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;//printf("ins..............................\n");for(m=1;m<=n*n;m++){a[x][y]=m;if(m%n!=0){//后面的每一个数存放的行比前一个数的行数减1,列数加1x--;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 && std::abs(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;}} }