1、奇数阶魔方阵的数字规律
(1)自然数1出现在第一行的正中间;
(2)若填入的数字在第一行(不在第n列),则下一个数字在第n行(最后一行)且列数加1(列数右移一列);
(3)若填入的数字在该行的最右侧,则下一个数字就填在上一行的最左侧;
(4)一般地,下一个数字在前一个数字的右上方(行数少1,列数加1);
(5)若应填的地方已经有数字或在方阵之外,则下一个数字就填在前一个数字的下方。(一般地,n的倍数的下一个数字是在该数的下方。)
//奇数魔方阵
void Magic1()
{
#define ROW 5//定义宏行数为5
#define COL ROW//定义宏列数等于行数,则一共要放1~25这25个数
assert(ROW%2 != 0);//断言判断是否为奇数阶
int arr[ROW][COL] = {0};//将二维数组初始化为0
int currow = 0;//指向第一行
int curcol = COL/2;//指向中间那列
arr[currow][curcol] = 1;//将第一行中间的数赋值为1,第一个数存入了二维数组
for(int i=2; i<=ROW*COL; i++)//从2开始放,终止条件是25存入二维数组
{
if(arr[(currow-1+ROW)%ROW][(curcol+1)%COL] == 0)//i存放的位置是上一个的上一行且为下一列的这个位置,但要保证这个位置没有存放数,此处值为0代表没有被占领
{
currow = (currow-1+ROW)%ROW;//更新行
curcol = (curcol+1)%COL;//更新列
}
else//如果上一行下一列的位置被占领,则放在上一个位置的下一列这个位置,行不变
{
currow = (currow+1)%ROW;//只更新列
}
arr[currow][curcol] = i;
}
for(int i=0; i<ROW; i++)//打印
{
for(int j=0; j<COL; j++)
{
printf("%-3d", arr[i][j]);
}
printf("\n");
}
}
int main()
{
Magic1();//调用
return 0;
}
2、偶数魔方阵
(1)不能被4整除
偶数魔方阵,且不能被4整除 (4K+2)
1.将其划分4个奇数魔方阵,左上角将1~ROW*COL/4,按照奇数魔方阵的规则放进去,接下来是右下,右上,左下,依次赋值
上下标记的数字进行交换
标记的规则:
1.右半边大于k+2的列(从1开始)
2.左半边,上下两个块最中心的点进行交换
3.左半边小于中心列的列(除了上下半边最中心的行的第一列的那个值不用交换)(从1开始)
void Magic3()
{
#define ROW 10
#define COL ROW
assert(ROW%2==0 && ROW%4!=0);
int arr[ROW][COL] = {0};
int currow = 0;
int curcol = ROW/4;
arr[currow][curcol] = 1;
//左上角
for(int i=2; i<=ROW*COL/4; i++)
{
if(arr[(currow-1+ROW/2)%(ROW/2)][(curcol+1)%(COL/2)] == 0)
{
currow = (currow-1+ROW/2)%(ROW/2);
curcol = (curcol+1)%(COL/2);
}
else
{
currow = (currow+1)%(ROW/2);
}
arr[currow][curcol] = i;
}
//右下角
currow = ROW/2;
for(int i=0; i<ROW/2; i++, currow++)
{
curcol = COL/2;
for(int j=0; j<COL/2; j++,curcol++)
{
arr[currow][curcol] = arr[i][j]+(ROW*COL/4);
//curcol++;
}
//currow++;
}
//右上角
currow = 0;
for(int i=ROW/2; i<ROW; i++, currow++)
{
curcol = COL/2;
for(int j=COL/2; j<COL; j++,curcol++)
{
arr[currow][curcol] = arr[i][j]+(ROW*COL/4);
//curcol++;
}
//currow++;
}
//左下角
currow = ROW/2;
for(int i=0; i<ROW/2; i++, currow++)
{
curcol = 0;
for(int j=COL/2; j<COL; j++,curcol++)
{
arr[currow][curcol] = arr[i][j]+(ROW*COL/4);
//curcol++;
}
//currow++;
}
//2.改标记点,先改右半边大于k+2的列 k=ROW/4 右半边的k=ROW/4+ROW/2 右半边的k+2 = ROW/4+ROW/2+2
for(int j=ROW/4+ROW/2+2; j<COL; j++)//j现在就指向大于k+2的那一列 如果j合法,则上下交换
{
for(int i=0; i<ROW/2; i++)
{
int tmp = arr[i][j];
arr[i][j] = arr[i+ROW/2][j];
arr[i+ROW/2][j] = tmp;
}
}
//3.左半边,上下两个块的中心点
int tmp = arr[ROW/4][COL/4];
arr[ROW/4][COL/4] = arr[ROW/4+ROW/2][COL/4];
arr[ROW/4+ROW/2][COL/4] = tmp;
//4.左半边小于k+1的列(除了上下半边最中心的行的第一列的那个值不用交换)(从1开始)
for(int i=0; i<ROW/2; i++)
{
for(int j=0; j<ROW/4; j++)
{
if(i==ROW/4 && j==0)
{
continue;
}
int tmp = arr[i][j];
arr[i][j] = arr[i+ROW/2][j];
arr[i+ROW/2][j] = tmp;
}
}
for(int i=0; i<ROW; i++)
{
for(int j=0; j<COL; j++)
{
printf("%-3d", arr[i][j]);
}
printf("\n");
}
}
int main()
{
Magic3();
return 0;
}
(2)能被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:填完数据后则完成 双偶数魔方阵;
void Magic2()
{
#define ROW 8
#define COL ROW
assert(ROW%2==0 && ROW%4==0);
int arr[ROW][COL] = {0};
int tmp = 1;
for(int i=0; i<ROW; i++)
{
for(int j=0; j<COL; j++)
{
arr[i][j] = tmp++;
}
}
int row1 = 0;//主对角线行
int col1 = 0;//主对角线列
int row2 = 0;//副对角线行
int col2 = 0;//副对角线列
//总体划分K*K块(i*j)
for(int i=0; i<(ROW/4); i++)//i指向行
{
for(int j=0; j<COL/4; j++)//j指向列
{
row1 = 4*i;
col1 = 4*j;
row2 = 4*i;
col2 = 4*j+3;
for(int k=0; k<4; k++)
{
arr[row1][col1] = (ROW*COL+1) - arr[row1][col1];
arr[row2][col2] = (ROW*COL+1) - arr[row2][col2];
row1++;
col1++;
row2++;
col2--;
}
}
}
for(int i=0; i<ROW; i++)
{
for(int j=0; j<COL; j++)
{
printf("%-3d", arr[i][j]);
}
printf("\n");
}
#undef ROW
#undef COL
}
int main()
{
Magic2();
return 0;