标签:
/* 幻方的计算: 计算任意阶数幻方的各行、各列、各条对角线上所有数的和的公式为: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"); /* 测试每一行的和是否为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; //printf("ins..............................\n"); 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 && 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; } } }
标签:
原文地址:http://www.cnblogs.com/chenhuan001/p/5798519.html