魔方阵 奇数偶数都成立

 

《C程序设计(第四版)》 谭浩强的,第六章 第7题 有一个输出 魔方阵的题,相信困惑了不少人,下面本文给予大家完整的解答。

所谓魔方阵即1-N*N个数排成一个n阶矩阵,矩阵特点:每一行,每一列,对角线之和都等于相同的值。

下面根据资料总结得到:

1):奇数的魔方阵:

其数字排列规则如下:

    1)将1填入第一行中间;

  2)将每个数填在前一个数的右上方。

  3)若该位置超出最上行,则改填在最下行的对应位置;

  4)若该位置超出最右列,则该填在最左列的对应行位置;

  5)若某元素填在第一行最右列,下一个数填在该数同列的下一行;

  6)若某数已找到了填写位置,但其已填了其他数据,则这个数应填在应该填的位置的同列的下一行位置。

 

自己的代码如下:

#include<stdio.h> //此为求奇魔方阵的方法
#include<string.h>
int main()
{
int a[100][100],i,j,n,k,x,y;
printf("Enter n:\n");
while(scanf("%d",&n)!=EOF&&(n%2==1))
{
memset(a,0,sizeof(a));//将原始数组全部清0;必须清零
i=0;
j=n/2;
a[i][j]=1; //第一条
for(k=2;k<=n*n;k++)
{
x=i; //x,y记录原来一个数的坐标
y=j;
i--;
j++;
if(i<0)i=n-1; //第二条
if(j>n-1)j=0; //第三条
if(a[0][n-1]!=0)//第四条 此条可以省略
{
a[1][n-1]=a[0][n-1]+1;
}
if(a[i][j]!=0)// 第五条
{
i=x+1;
j=y;
}
a[i][j]=k;

}

for(i=0;i<n;i++) //输出此数组
{
for(j=0;j<n;j++)
printf("%4d",a[i][j]);
putchar('\n');
}
printf("Enter n:\n");
}
return 0;
}

 

2):双偶数魔方阵:

所谓双偶数即2*(2m)的数据,即4的整数倍,期排列特点如下:

1:把魔方阵分为上下左右4个n/2*n/2的小的方阵,左上角和右下角的n/2*n/2的小矩阵

2:偶行偶列,奇行奇列赋值为0,其余赋值为1;右上角和左上角的n/2*n/2的小矩阵,偶行奇列,奇行偶列赋值为0,其余赋值为1。

3:从魔方阵由左到右,由上到下开始赋值,赋值为从n*n到1,若遇到原来填入方阵中的0,则跳过此格;

4:从魔方阵由左到右,由上到下开始赋值,赋值为从1到n*n,若遇到原来填入方阵中的1,则跳过此格;

5:填完数据后则完成 双偶数魔方阵;

我的代码如下:

#include<stdio.h>//双偶数的魔方阵 即4*m阶 (m=1,2,3...)
#include<string.h>
int main()
{
int n,a[100][100],i,j,k;
while(scanf("%d",&n)!=EOF&&(n%4==0)&&n>0)
{
memset(a,0,sizeof(a));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(i<n/2&&j<n/2||i>=n/2&&j>=n/2) //分别填入 0和1
if(i%2==0&&j%2==1||i%2==1&&j%2==0)
a[i][j]=1;
if(i>=n/2&&j<n/2||i<n/2&&j>=n/2)
if(i%2==0&&j%2==0||i%2==1&&j%2==1)
a[i][j]=1;
}
k=n*n;
for(i=0;i<n;i++) //填入n*n到1
for(j=0;j<n;j++)
{
if(a[i][j]==1)a[i][j]=k;
k--;
}
k=1;
for(i=0;i<n;i++)//填入1到n*n 并输出魔方阵
{
for(j=0;j<n;j++)
{
if(a[i][j]==0)a[i][j]=k;
k++;
printf("%4d",a[i][j]);
}
putchar('\n');
}
}
}


3):单偶数魔方阵

所谓单偶数,即n=2*(2m+1)的数据,其数字排列特点如下:

1:将矩阵分为4个区,A、B、C、D区,其相对位置如下:

A C
D B


2:先把数字1到(n/2)*(n/2)按照奇数魔方阵的方法填入A中,然后把其每一个数据分别加上(n/2)*(n/2)填入到B中,再把B中的数据加上(n/2)*(n/2)填入到C中,再把C中的数据加上(n/2)*(n/2)填入到D中;

3:交换数字

需要交换的数字的规则:

1: 右边两个小方阵中大于(m+2)的列中所有的数字
2
: 左边两个小方阵中(m+1,m+1)这一个方格的数字
3
: 左边两个小方阵中除(m+1,1)格位之外,小于m+1的列中的所有数字

其中n=2*(2m+1);即m=(n-2)/4;

比如说n=6,即m=1这个例子;

先把这些数字做标记:如图

只需要标记A区和C区数字即可,然后A区和D区数字对应交换,

C区和B区数字对应进行交换,此例C区没有交换数字:

26 19 24
3 5 7 21 23 25
4 9 2 22 27 20
35 28 33 17 10 15
30 32 34 12 14 16
31 36 29 13 18 11

 

然后交换即得到单偶数魔方阵:如下图:

 

35 26 19 24
3 32 7 21 23 25
31 9 2 22 27 20
8 28 33 17 10 15
30 5 34 12 14 16
4 36 29 13 18 11

代码如下:

#include<stdio.h>  // A  C      A、B、C、D四块的相对位置
#include<string.h> // D B
#define M 100
void output(int a[][M],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%4d",a[i][j]);
printf("\n");
}
}
int main()
{
int a[100][100],i,j,k,x,y,n,m,t;
printf("请输入单偶数n:\n");
while(scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));

//输入A矩阵
a[0][n/2/2]=1;
i=0;
j=n/2/2;
for(k=2;k<=(n/2*n/2);k++)
{
x=i;
y=j;
i--;
j++;
if(i<0)i=n/2-1;
if(j>n/2-1)j=0;
if(a[i][j]!=0)
{
i=x+1;
j=y;
}
a[i][j]=k;
}
//输入B矩阵
for(i=n/2;i<n;i++)
for(j=n/2;j<n;j++)
{
a[i][j]=a[i-n/2][j-n/2]+(n/2)*(n/2);
}
//C...
for(i=0;i<n/2;i++)
for(j=n/2;j<n;j++)
{
a[i][j]=a[i+n/2][j]+(n/2)*(n/2);
}
//D...
for(i=n/2;i<n;i++)
for(j=0;j<n/2;j++)
{
a[i][j]=a[i-n/2][j+n/2]+(n/2)*(n/2);
}


//交换数字
//A和D换 因为n=2*(2m+1),所以m=(n-2)/4

//步骤1: 交换第(m+1,m+1)格
m=(n-2)/4;
t=a[m][m];
a[m][m]=a[m+n/2][m];
a[m+n/2][m]=t;
//2:交换除了(m+1,1)格以外的小于m+1的列
for(i=0;i<n/2;i++)
for(j=0;j<n/2;j++)
{
if(j<m)
{
               if(i==m&&j==0)continue;
t=a[i][j];
a[i][j]=a[i+n/2][j];
a[i+n/2][j]=t;
}
}
//C和B的交换

for(i=0;i<n/2;i++)
for(j=n/2;j<n;j++)
{
if(j>n/2+m+1)
{
t=a[i][j];
a[i][j]=a[i+n/2][j];
a[i+n/2][j]=t;
}
}

output(a,n); //输出魔方阵
printf("请输入单偶数n:\n");
}

return 0;
}

好了,这就是1--n阶的魔方阵,当然魔方阵的排列规则有很多,还可以构造魔方阵,只要记住其中一种方法就可以了,若要看整合的代码,并带有检测是否为魔方阵的环节,请看下篇魔方阵(2),这就是魔方阵的全面解答,与大家分享,此文若有有不足之处或错误请指正;

posted @ 2012-03-08 16:37  龙杉老师  阅读(4337)  评论(4编辑  收藏  举报