幻方(魔方阵)
一、幻方
幻方(Magic Square)是一种将数字安排在正方形格子中,使每行、列和对角线上的数字和都相等的方法。
二、幻方种类及构造原理
1.奇数阶幻方
即 N 为奇数的 N x N 的矩阵。
本例使用罗(萝)伯(卜)法生成奇数幻方:
- 将 1 放在第一行中间一列。
- 从 2 开始直到n×n止各数依次按下列规则存放:
按 45° 方向(右上方)行走,即每一个数存放的行比前一个数的行数减1,列数加1。 - 如果行列范围超出矩阵范围,则回绕。
例如当前位置在第 1 行,则下一个位置应在第N行,列数同样加1;例如当前位置在第N列,则下一个位置应在第一列,行数同样减1。 - 如果按上面规则确定的位置上已有数,或上一个数是第 1 行第 n 列时,则把下一个数放在上一个数的下面。
代码如下:
void Odd_magic(int array[n][n])
{
int k = 1; //k为已填元素的个数
int row = 0, column = (int)n / 2; //起始点
array[0][(int)n / 2] = 1; //起始点的值
while(k <= n * n) //填完即跳出
{
if(column != n - 1 && row != 0) //判断是否不在第一行,不在第N列
{
if(array[row - 1][column + 1] == 0) //判断下一个点的值是否为零
{
array[row - 1][column + 1] = array[row][column] + 1; //标记右上方
row = row - 1; column = column + 1; //每标记一个点,一定要更换标注点的位置,以下都是
k++; //每标记一个点就加一,以下都是
}
}
if(row == 0 && column != n - 1) //判断是否在第一行
{
array[n - 1][column + 1] = array[row][column] + 1;
row = n - 1;
column = column + 1;
k++;
}
if(column == n - 1 && row != 0) //判断是否在第N列
{
array[row - 1][0] = array[row][column] + 1;
row = row - 1;
column = 0;
k++;
}
if(((column != n - 1 && row != 0) && (array[row - 1][column + 1] != 0)) || (row == 0 && column == n - 1)) //判断是否在第一行或者第一列,右上方是否为零,是否在第一行第N列
{
array[row + 1][column] = array[row][column] + 1;
row = row + 1;
k++;
}
}
}
2.双偶数阶幻方
即 N 为4m(4的倍数)的 N x N 的矩阵。将矩阵分成四个区域,即:
A | C |
---|---|
D | B |
本例使用Spring法生成双偶幻方:
- 将1放在幻方的任意一个角格,然后按从左到右、从上到下的顺序依次填写其余数,当然也可以是从上到下、从左到右的顺序。因此,每个角可以按两个方向的顺序来填写。
- 进行对称交换。以幻方中心点为对称点,将 A 区域的 row + column 为偶数的数字与 B 区域对应的数字进行交换;将 C 区域的 row + column 为奇数的数字与 D 区域对应的数字进行交换。(保证 不同时 为奇或偶即可。)
代码如下:
void Double_even_magic(int (*array)[N])
{
int count = 1, row, column, temp;
//第一步填写矩阵
for(row = 0; row < N; row++)
for(column = 0; column < N; column++)
array[row][column] = count++;
//第二步对称交换
for(row = 0; row < N / 2; row++)
{
//交换A,B关于中心对称的值
for(column = 0; column < N / 2; column++)
{
//exchange(&a[row][column], &a[N - 1 - row][N - 1 - column]);
if((row + column) % 2 == 0)
{
temp = array[row][column];
array[row][column] = array[N - 1 - row][N - 1 - column];
array[N - 1 - row][N - 1 - column] = temp;
}
}
//交换C,D关于中心对称的值
for(column = N / 2; column < N; column++)
{
if((row + column) % 2)
{
temp = array[row][column];
array[row][column] = array[N - 1 - row][N - 1 - column];
array[N - 1 - row][N - 1 - column] = temp;
}
}
}
}
3.单偶数阶幻方
即 N 为4m + 2(2的倍数,不是4的倍数)的 N x N 的矩阵。将矩阵分成四个区域,即:
A | C |
---|---|
D | B |
本例使用Strachey法生成单偶幻方(基于奇数阶幻方之上):
- A区域用 1 至 (2m+1)2 填写成 2m+1 阶幻方;B区域用 (2m+1)2+1 至 2*(2m+1)2 填写成 2m+1 阶幻方;C区域用 2*(2m+1)2+1 至 3*(2m+1)2 填写成 2m+1 阶幻方;D区域用 3*(2m+1)2+1 至 4*(2m+1)2 =填写成 2m+1 阶幻方;
- 在A区域取左侧 m 列与D区域对应小格对调,在A区域中间行取中心格与其他行左侧一格与D区域对应小格对调(也就是,最中间的数字、中间一行从左向右前 m-1 个数字,其他行前 m 个数字)。在C区域中任取 m-1 列与B区域对应小格对调。
代码如下:
void Single_even_magic(int array[N][N])
{
int count = 1, row, column, m = (int)N / 4, temp;
int A[n][n] = {0}, B[n][n] = {0}, C[n][n] = {0}, D[n][n] = {0}; //初始化A,B,C,D
//第一步,完成A, B, C, D幻方
Odd_magic(A);
for(row = 0; row < n; row++)
{
for(column = 0; column < n; column++)
{
B[row][column] = A[row][column] + (2 * m + 1) * (2 * m + 1);
C[row][column] = B[row][column] + (2 * m + 1) * (2 * m + 1);
D[row][column] = C[row][column] + (2 * m + 1) * (2 * m + 1);
}
}
// print(A, B, C, D);
//第二步,完成A, D的对调,C, B的对调
//完成A, D的对调
for(row = 0; row < n; row++)
{
for(column = 0; column < m; column++)
{
temp = A[row][column];
A[row][column] = D[row][column];
D[row][column] = temp;
}
}
temp = A[m][m]; A[m][m] = D[m][m]; D[m][m] = temp;
temp = A[m][m - 1]; A[m][m - 1] = D[m][m - 1]; D[m][m - 1] = temp;
//完成C, B的对调
for(row = 0; row < n; row++)
{
for(column = 0; column < m - 1; column++)
{
temp = B[row][column];
B[row][column] = C[row][column];
C[row][column] = temp;
}
}
// print(A, B, C, D);
//将A, B, C, D对应区域赋值到array中
for(row = 0; row < N; row++)
{
for(column = 0; column < N; column++)
{
if(row < n && column < n)
array[row][column] = A[row][column];
else if(row < n && column >= n)
array[row][column] = C[row][column - n];
else if(row >= n && column < n)
array[row][column] = D[row - n][column];
else if(row >= n && column >= n)
array[row][column] = B[row - n][column - n];
}
}
}
三、整体代码
最后附上总代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define N 3 //幻方阶数
#if (N % 2 == 0 && N % 4 != 0)
#define n N / 2 //单偶
#else
#define n N //双偶、奇数
#endif
void Odd_magic(int array[n][n]); //生成奇数阶幻方
void Double_even_magic(int (*array)[N]); //生成双偶数阶幻方
void Single_even_magic(int array[N][N]); //生成单偶数阶幻方
int check(int array[N][N]); //检查生成的幻方是否正确,即行、列、对角线和是否相等
void print(int (*A)[n], int (*B)[n], int (*C)[n], int (*D)[n]); //打印A, B, C, D幻方
void exchange(int *x, int *y); //交换两个整形变量的值
int main()
{
int row, column,a[N][N] = {0};
Odd_magic(a); //测试奇数阶幻方
// Double_even_magic(a); //测试双偶数阶幻方
// Single_even_magic(a); //测试单偶数阶幻方
if(!check(a))
{
for(row = 0; row < N; row++)
{
for(column = 0; column < N; column++)
printf("%4d ", a[row][column]);
printf("\n");
}
}
system("pause");
return 0;
}
void Odd_magic(int array[n][n])
{
int k = 1; //k为已填元素的个数
int row = 0, column = (int)n / 2; //起始点
array[0][(int)n / 2] = 1; //起始点的值
while(k <= n * n) //填完即跳出
{
if(column != n - 1 && row != 0) //判断是否不在第一行,不在第N列
{
if(array[row - 1][column + 1] == 0) //判断下一个点的值是否为零
{
array[row - 1][column + 1] = array[row][column] + 1; //标记右上方
row = row - 1; column = column + 1; //每标记一个点,一定要更换标注点的位置,以下都是
k++; //每标记一个点就加一,以下都是
}
}
if(row == 0 && column != n - 1) //判断是否在第一行
{
array[n - 1][column + 1] = array[row][column] + 1;
row = n - 1;
column = column + 1;
k++;
}
if(column == n - 1 && row != 0) //判断是否在第N列
{
array[row - 1][0] = array[row][column] + 1;
row = row - 1;
column = 0;
k++;
}
if(((column != n - 1 && row != 0) && (array[row - 1][column + 1] != 0)) || (row == 0 && column == n - 1)) //判断是否在第一行或者第一列,右上方是否为零,是否在第一行第N列
{
array[row + 1][column] = array[row][column] + 1;
row = row + 1;
k++;
}
}
}
void Double_even_magic(int (*array)[N])
{
int count = 1, row, column, temp;
//第一步填写矩阵
for(row = 0; row < N; row++)
for(column = 0; column < N; column++)
array[row][column] = count++;
//第二步对称交换
for(row = 0; row < N / 2; row++)
{
//交换A,B关于中心对称的值
for(column = 0; column < N / 2; column++)
{
//exchange(&a[row][column], &a[N - 1 - row][N - 1 - column]);
if((row + column) % 2 == 0)
{
temp = array[row][column];
array[row][column] = array[N - 1 - row][N - 1 - column];
array[N - 1 - row][N - 1 - column] = temp;
}
}
//交换C,D关于中心对称的值
for(column = N / 2; column < N; column++)
{
if((row + column) % 2)
{
temp = array[row][column];
array[row][column] = array[N - 1 - row][N - 1 - column];
array[N - 1 - row][N - 1 - column] = temp;
}
}
}
}
void Single_even_magic(int array[N][N])
{
int count = 1, row, column, m = (int)N / 4, temp;
int A[n][n] = {0}, B[n][n] = {0}, C[n][n] = {0}, D[n][n] = {0}; //初始化A,B,C,D
//第一步,完成A, B, C, D幻方
Odd_magic(A);
for(row = 0; row < n; row++)
{
for(column = 0; column < n; column++)
{
B[row][column] = A[row][column] + (2 * m + 1) * (2 * m + 1);
C[row][column] = B[row][column] + (2 * m + 1) * (2 * m + 1);
D[row][column] = C[row][column] + (2 * m + 1) * (2 * m + 1);
}
}
// print(A, B, C, D);
//第二步,完成A, D的对调,C, B的对调
//完成A, D的对调
for(row = 0; row < n; row++)
{
for(column = 0; column < m; column++)
{
temp = A[row][column];
A[row][column] = D[row][column];
D[row][column] = temp;
}
}
temp = A[m][m]; A[m][m] = D[m][m]; D[m][m] = temp;
temp = A[m][m - 1]; A[m][m - 1] = D[m][m - 1]; D[m][m - 1] = temp;
//完成C, B的对调
for(row = 0; row < n; row++)
{
for(column = 0; column < m - 1; column++)
{
temp = B[row][column];
B[row][column] = C[row][column];
C[row][column] = temp;
}
}
// print(A, B, C, D);
//将A, B, C, D对应区域赋值到array中
for(row = 0; row < N; row++)
{
for(column = 0; column < N; column++)
{
if(row < n && column < n)
array[row][column] = A[row][column];
else if(row < n && column >= n)
array[row][column] = C[row][column - n];
else if(row >= n && column < n)
array[row][column] = D[row - n][column];
else if(row >= n && column >= n)
array[row][column] = B[row - n][column - n];
}
}
}
int check(int array[N][N])
{
int i, j, value[5] = {0};
for(j = 0; j < N; j++)
value[0] += array[0][j];
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
value[1] += array[i][j];
value[2] += array[j][i];
if(i + j == N - 1)
value[4] += array[i][j];
if(i == j)
value[3] += array[i][j];
}
if(value[0] == value[1] && value[0] == value[2])
{value[1] = 0; value[2] = 0;}
else
return -1;
}
if(value[0] == value[3] && value[0] == value[4])
return 0;
}
void print(int (*A)[n], int (*B)[n], int (*C)[n], int (*D)[n])
{
int row, column;
printf("A:\n");
for(row = 0; row < n; row++)
{
for(column = 0; column < n; column++)
printf("%4d", A[row][column]);
printf("\n");
}
printf("B:\n");
for(row = 0; row < n; row++)
{
for(column = 0; column < n; column++)
printf("%4d", B[row][column]);
printf("\n");
}
printf("C:\n");
for(row = 0; row < n; row++)
{
for(column = 0; column < n; column++)
printf("%4d", C[row][column]);
printf("\n");
}
printf("D:\n");
for(row = 0; row < n; row++)
{
for(column = 0; column < n; column++)
printf("%4d", D[row][column]);
printf("\n");
}
printf("\n");
}
void exchange(int *x, int *y)
{
int temp;
temp = *y;
*y = *x;
*x = temp;
}