题目:
输出魔方阵,所谓魔方阵是指这样的方阵,它的每一行,每一列和对角线的和均相等,要输出1-n^2个自然数构成的魔方阵,例如
8 1 6
3 5 7
4 9 2
解决方案
- 当n<=2时不存在魔方矩阵
if(n<3){
printf("不存在n=%d的魔方矩阵",n);
return;
}
- 当n为奇数时,可用“罗泊法”即
⑴将1放在第一行中间一列;
⑵从2开始直到n×n止各数依次按下列规则存放;每一个数存放的行比前一个数的行数减1,列数加1(例如上面的三阶魔方阵,5在4的上一行后一列);
⑶如果上一个数的行数为1,则下一个数的行数为n(指最下一行);例如1在第一行,则2应放在最下一行,列数同样加1;
⑷当上一个数的列数为n时,下一个数的列数应为1,行数减去1。例如2在第3行最后一列,则3应放在第二行第一列;
⑸如果按上面规则确定的位置上已有数,或上一个数是第一行第n列时,则把下一个数放在上一个数的下面。例如按上面的规定,4应该放在第1行第2列,但该位置已经被占据,所以4就放在3的下面。
if(n%2==1){
int count=1;
int i=0,j=n/2;
a[i][j]=count++;
for(int temp=0;temp<n*n-1;temp++){
if(a[(i-1+n)%n][(j+1+n)%n]!=0)
i=(i+1+n)%n;
else{
i=(i-1+n)%n;
j=(j+1+n)%n;
}
a[i][j]=count++;
}
}
3.当n为偶数时,又分为两种情况,即n能否被4整除
当n能被4整除时,方案如下
(1) 先将整个方阵划分成k*k个4阶方阵,然后在每个4阶方阵的对角线上做记号;
(2) 由左而右、由上而下,遇到没有记号的位置才填数字,但不管是否填入数字,每移动一格数字都要加1;
(3) 自右下角开始,由右而左、由下而上,遇到没有数字的位置就填入数字,但每移动一格数字都要加1。
if(n%4==0){
int num=n/4;
for(int i=0;i<num;i++)
for(int j=0;j<num;j++){
a[4*i+0][4*j+0]=-1;
a[4*i+0][4*j+3]=-1;
a[4*i+1][4*j+1]=-1;
a[4*i+1][4*j+2]=-1;
a[4*i+2][4*j+1]=-1;
a[4*i+2][4*j+2]=-1;
a[4*i+3][4*j+0]=-1;
a[4*i+3][4*j+3]=-1;
}
int count=1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(a[i][j]==0)
a[i][j]=count++;
for(int i=n-1;i>=0;i--)
for(int j=n-1;j>=0;j--)
if(a[i][j]==-1)
a[i][j]=count++;
}
当n不能被4整除时,方案如下
填制魔方阵时,先将整个方阵划成田字型的四个2 k + 1阶的奇数阶小方阵,并以下法做注记:
(1)右半两个小方阵中大于k+2的列;
(2)左半两个小方阵中( k + 1 , k + 1 )的格位;
(3)左半两个小方阵中除了( k+1 , 1 )是指第一列第k+1行的格位之外,小于k +1的列。
以奇数阶魔方阵的方法连续填制法依左上、右下、右上、左下的顺序分别填制这四个小方阵。将上半及下半方阵中有注记的数字对调,魔方阵完成。
if(n%4==2){
int num=n/2;
int count=1;
int sym=1,x=0,y=0;
while(sym!=0){
int i=0,j=num/2;
a[i+x][j+y]=count++;
for(int temp=0;temp<num*num-1;temp++){
if(a[(i-1+num)%num+x][(j+1+num)%num+y]!=0)
i=(i+1+num)%num;
else{
i=(i-1+num)%num;
j=(j+1+num)%num;
}
a[i+x][j+y]=count++;
}
switch(sym){
case 1:x+=num; y+=num; sym=2; break;
case 2:x-=num; sym=3; break;
case 3:x+=num; y-=num; sym=4; break;
case 4:sym=0; break;
}
}
int k=(n-2)/4;
for(int j=num+k+2;j<n;j++){ //1
for(int i=0;i<num;i++){
int temp=a[i][j];
a[i][j]=a[i+num][j];
a[i+num][j]=temp;
}
}
int temp=a[k][k]; a[k][k]=a[k+num][k]; a[k+num][k]=temp; //2
for(int j=0;j<k;j++)
for(int i=0;i<num;i++)
if(i!=k){
int temp=a[i][j];
a[i][j]=a[i+num][j];
a[i+num][j]=temp;
}
}
运行结果如下
n=10
n=8
n=9
完整代码示例
void function4(int n){//魔方矩阵
int a[100][100];
memset(a,0,sizeof(a));
if(n<3){
printf("不存在n=%d的魔方矩阵",n);
return;
}
if(n%2==1){
int count=1;
int i=0,j=n/2;
a[i][j]=count++;
for(int temp=0;temp<n*n-1;temp++){
if(a[(i-1+n)%n][(j+1+n)%n]!=0)
i=(i+1+n)%n;
else{
i=(i-1+n)%n;
j=(j+1+n)%n;
}
a[i][j]=count++;
}
}
if(n%4==0){
int num=n/4;
for(int i=0;i<num;i++)
for(int j=0;j<num;j++){
a[4*i+0][4*j+0]=-1;
a[4*i+0][4*j+3]=-1;
a[4*i+1][4*j+1]=-1;
a[4*i+1][4*j+2]=-1;
a[4*i+2][4*j+1]=-1;
a[4*i+2][4*j+2]=-1;
a[4*i+3][4*j+0]=-1;
a[4*i+3][4*j+3]=-1;
}
int count=1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(a[i][j]==0)
a[i][j]=count++;
for(int i=n-1;i>=0;i--)
for(int j=n-1;j>=0;j--)
if(a[i][j]==-1)
a[i][j]=count++;
}
if(n%4==2){
int num=n/2;
int count=1;
int sym=1,x=0,y=0;
while(sym!=0){
int i=0,j=num/2;
a[i+x][j+y]=count++;
for(int temp=0;temp<num*num-1;temp++){
if(a[(i-1+num)%num+x][(j+1+num)%num+y]!=0)
i=(i+1+num)%num;
else{
i=(i-1+num)%num;
j=(j+1+num)%num;
}
a[i+x][j+y]=count++;
}
switch(sym){
case 1:x+=num; y+=num; sym=2; break;
case 2:x-=num; sym=3; break;
case 3:x+=num; y-=num; sym=4; break;
case 4:sym=0; break;
}
}
int k=(n-2)/4;
for(int j=num+k+2;j<n;j++){ //1
for(int i=0;i<num;i++){
int temp=a[i][j];
a[i][j]=a[i+num][j];
a[i+num][j]=temp;
}
}
int temp=a[k][k]; a[k][k]=a[k+num][k]; a[k+num][k]=temp; //2
for(int j=0;j<k;j++)
for(int i=0;i<num;i++)
if(i!=k){
int temp=a[i][j];
a[i][j]=a[i+num][j];
a[i+num][j]=temp;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("%3d ",a[i][j]);
printf("\n");
}
}