幻方(魔方阵)

幻方(魔方阵)


一、幻方

幻方(Magic Square)是一种将数字安排在正方形格子中,使每行、列和对角线上的数字和都相等的方法。

二、幻方种类及构造原理

1.奇数阶幻方

即 N 为奇数的 N x N 的矩阵。

本例使用罗(萝)伯(卜)法生成奇数幻方:

  1. 将 1 放在第一行中间一列。
  2. 从 2 开始直到n×n止各数依次按下列规则存放:
    45° 方向(右上方)行走,即每一个数存放的行比前一个数的行数减1,列数加1
  3. 如果行列范围超出矩阵范围,则回绕。
    例如当前位置在第 1 行,则下一个位置应在第N行,列数同样加1;例如当前位置在第N列,则下一个位置应在第一列,行数同样减1。
  4. 如果按上面规则确定的位置上已有数,或上一个数是第 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 的矩阵。将矩阵分成四个区域,即:

AC
DB

本例使用Spring法生成双偶幻方:

  1. 将1放在幻方的任意一个角格,然后按从左到右、从上到下的顺序依次填写其余数,当然也可以是从上到下、从左到右的顺序。因此,每个角可以按两个方向的顺序来填写。
  2. 进行对称交换。以幻方中心点为对称点,将 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 的矩阵。将矩阵分成四个区域,即:

AC
DB

本例使用Strachey法生成单偶幻方(基于奇数阶幻方之上):

  1. 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 阶幻方;
  2. 在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;
}

参考

幻方法则
单偶幻方的填法
单偶数幻方构造法

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

paopol

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值