任意阶幻方(魔方矩阵)C语言实现

魔方又称幻方纵横图九宫图,最早记录于我国古代的洛书。据说夏禹治水时,河南洛阳附近的大河里浮出了一只乌龟,背上有一个很奇怪的图形,古人认为是一种祥瑞,预示着洪水将被夏禹王彻底制服。后人称之为"洛书"或"河图",又叫河洛图

南宋数学家杨辉,在他著的《续古摘奇算法》里介绍了这种方法:只要将九个自然数按照从小到大的递增次序斜排,然后把上、下两数对调,左、右两数也对调;最后再把中部四数各向外面挺出,幻方就出现了。 (摘自《趣味数学辞典》)

在西方,阿尔布雷特·丢勒于1514年创作的木雕《忧郁》是最早关于魔方矩阵的记载。有学者认为,魔方矩阵和风靡一时的炼金术有关。几个世纪以来,魔方矩阵吸引了无数的学者和数学爱好者。本杰明·富兰克林就做过有关魔方矩阵的实验。

最简单的魔方就是平面魔方,还有立体魔方、高次魔方等。对于立体魔方、高次魔方世界上很多数学家仍在研究,本文只讨论平面魔方。

每行、每列及对角线之和被称为魔术常量或魔法总和,M。

其中,n为阶数。

例如,如果n=3,则M=[3*(3^2+1)]/2 = 15.

------------------来自百度

先标出引用地址:

http://blog.ddedu.com.cn/user1/88/archives/2007/2007420143329.shtml   //任意阶幻方构造方法

http://blog.csdn.net/cmutoo/article/details/5487157                                  //任意阶幻方C语言代码实现(有些许错误)

基础知识这里看:http://blog.csdn.net/oowgsoo/article/details/1567910

任意阶幻方的构造方法有很多种,所以要选定一种易于代码实现的一种

在上篇博客中说道:

/************************************************************************************

幻方的数量:
与我们大多数人的常识不同,幻方的数量不是唯一的,而且也不是一个简单的问题
3阶幻方只有1种
4阶幻方有880种,通过旋转和反射,总共可以有7040个幻方
5阶幻方有275 305 224个,这是用计算机算的
6阶幻方,大概是1.7743*10**19~1.7766*10**19之间,这是用统计学方法计算的,居然计算机也算不出来,更不要说6阶以上的幻方数量了

************************************************************************************/

所以代码实现的就有很大的局限性,只能实现某一种构造方法的幻方

幻方构造分为

1、奇数阶

2、双偶阶

3、单偶阶

三种。

对于奇数阶的幻方:

/*******************************************************************

n为奇数 (n=3,5,7,9,11……) (n=2×k+1,k=1,2,3,4,5……)

  奇数阶幻方最经典的填法是罗伯特法(也有人称之为楼梯法)。填写方法是这样:
  把1(或最小的数)放在第一行正中; 按以下规律排列剩下的n×n-1个数:
  (1)每一个数放在前一个数的右上一格;
  (2)如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列;
  (3)如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行;
  (4)如果这个数所要放的格已经超出了顶行且超出了最右列,那么就把它放在前一个数的下一行同一列的格内;
  (5)如果这个数所要放的格已经有数填入,处理方法同(4)。
  这种写法总是先向“右上”的方向,象是在爬楼梯。

*******************************************************************/

其实在C语言实现时是有潜在的规律的,当要填的数为n的倍数时,说明所要放的格已经有数填入

实现过程也是很巧妙……

void Odd(int n,int index)
{
    while(st != index)
    {
        cube[ox+stx][oy+sty] = st++;

        if((st-1) % n != 0)
        {
            stx--;
            sty++;
        }
        else
        {
            stx++;
        }

        stx = ((stx-1)%n+n)%n+1;
        sty = (sty%n == 0 ? n : sty%n);

    }
}

对于双偶数阶的

就是一个中心对称

void DouEven(int n)
{
    int i,j;
    int st = 1;
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
        {
            cube[i][j] = st++;
        }
    }

    int zx,zy,fx,fy;
    for(i=4; i<=n*n; i+=4)
    {

        for(j=4; j<=n*n; j+=4)
        {
            zx=i-3,zy=j-3,fx=i,fy=j-3;
            cube[zx][zy]=n*n-cube[zx][zy]+1;
            cube[zx+1][zy+1]=n*n-cube[zx+1][zy+1]+1;
            cube[zx+2][zy+2]=n*n-cube[zx+2][zy+2]+1;
            cube[zx+3][zy+3]=n*n-cube[zx+3][zy+3]+1;

            cube[fx][fy]=n*n-cube[fx][fy]+1;
            cube[fx-1][fy+1]=n*n-cube[fx-1][fy+1]+1;
            cube[fx-2][fy+2]=n*n-cube[fx-2][fy+2]+1;
            cube[fx-3][fy+3]=n*n-cube[fx-3][fy+3]+1;
        }
    }
}

对于单偶数阶的,麻烦许多

因为要用到奇数阶的构造方法

void SingleEven(int n)
{
    int i,j;

    ox=oy=0;st=1;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*1/4+1);    //A

    ox=oy=n/2;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*2/4+1);    //D

    ox=0,oy=n/2;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*3/4+1);    //B

    ox=n/2,oy=0;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*4/4+1);    //C

    int k=(n-2)/4,tmp;
    for(j=1; j<=n/2; j++)
    {
        for(i=1; i<=k; i++)
        {
            if(j != (n/2+1)/2)
            {
                tmp = cube[j][i];
                cube[j][i] = cube[j+n/2][i];
                cube[j+n/2][i] = tmp;
            }
            else
            {
                tmp = cube[j][i+(n/2+1)/2-1];
                cube[j][i+(n/2+1)/2-1] = cube[j+n/2][i+(n/2+1)/2-1];
                cube[j+n/2][i+(n/2+1)/2-1] = tmp;
            }
        }
    }
    if(k-1)
    {
        for(i=1; i<=n/2; i++)
        {
            int tmpp = (3*n+2)/4-1;
            for(j=1; j<=k-1; j++)
            {
                tmp = cube[i][j+tmpp];
                cube[i][j+tmpp] = cube[i+n/2][j+tmpp];
                cube[i+n/2][j+tmpp] = tmp;

            }
        }
    }
}

最后贴一个完整的代码:

#include <stdio.h>
#include <string.h>

int cube[1000][1000];
int stx,sty;
int st;
int num;
int ox,oy;

void Odd(int n,int index)
{
    while(st != index)
    {
        cube[ox+stx][oy+sty] = st++;

        if((st-1) % n != 0)
        {
            stx--;
            sty++;
        }
        else
        {
            stx++;
        }

        stx = ((stx-1)%n+n)%n+1;
        sty = (sty%n == 0 ? n : sty%n);

    }
}

void DouEven(int n)
{
    int i,j;
    int st = 1;
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
        {
            cube[i][j] = st++;
        }
    }

    int zx,zy,fx,fy;
    for(i=4; i<=n*n; i+=4)
    {

        for(j=4; j<=n*n; j+=4)
        {
            zx=i-3,zy=j-3,fx=i,fy=j-3;
            cube[zx][zy]=n*n-cube[zx][zy]+1;
            cube[zx+1][zy+1]=n*n-cube[zx+1][zy+1]+1;
            cube[zx+2][zy+2]=n*n-cube[zx+2][zy+2]+1;
            cube[zx+3][zy+3]=n*n-cube[zx+3][zy+3]+1;

            cube[fx][fy]=n*n-cube[fx][fy]+1;
            cube[fx-1][fy+1]=n*n-cube[fx-1][fy+1]+1;
            cube[fx-2][fy+2]=n*n-cube[fx-2][fy+2]+1;
            cube[fx-3][fy+3]=n*n-cube[fx-3][fy+3]+1;
        }
    }
}

void SingleEven(int n)
{
    int i,j;

    ox=oy=0;st=1;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*1/4+1);    //A

    ox=oy=n/2;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*2/4+1);    //D

    ox=0,oy=n/2;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*3/4+1);    //B

    ox=n/2,oy=0;
    stx=1,sty=(n/2+1)/2;
    Odd(n/2,n*n*4/4+1);    //C

    int k=(n-2)/4,tmp;
    for(j=1; j<=n/2; j++)
    {
        for(i=1; i<=k; i++)
        {
            if(j != (n/2+1)/2)
            {
                tmp = cube[j][i];
                cube[j][i] = cube[j+n/2][i];
                cube[j+n/2][i] = tmp;
            }
            else
            {
                tmp = cube[j][i+(n/2+1)/2-1];
                cube[j][i+(n/2+1)/2-1] = cube[j+n/2][i+(n/2+1)/2-1];
                cube[j+n/2][i+(n/2+1)/2-1] = tmp;
            }
        }
    }
    if(k-1)
    {
        for(i=1; i<=n/2; i++)
        {
            int tmpp = (3*n+2)/4-1;
            for(j=1; j<=k-1; j++)
            {
                tmp = cube[i][j+tmpp];
                cube[i][j+tmpp] = cube[i+n/2][j+tmpp];
                cube[i+n/2][j+tmpp] = tmp;

            }
        }
    }
}

void print(int n)
{
    int i,j;

    for(i=1; i<=n; i++)
    {
        int sum = 0;
        for(j=1; j<=n ; j++)
        {
            sum += cube[i][j];
            printf("%4d",cube[i][j]);
        }
        printf("    sum = %d",sum);
        printf("\n");
    }
}

int main()
{

    int i,j,k,t,n,m;
    do
    {
        printf("Please Input n(3-17): ");
        scanf("%d",&n);
        if(n<3)continue;

        memset(cube,0,sizeof(cube));
        if(n % 2 == 1)
        {
            stx=1,sty=(n+1)/2;
            ox=oy=0;
            st=1;
            Odd(n,n*n+1);
            print(n);
        }
        else if(n % 4 == 0)
        {
            DouEven(n);
            print(n);
        }
        else if(n % 2 ==0 && n % 4 != 0)
        {

            SingleEven(n);
            print(n);
        }
    }while(1);

    return 0;
}

再上一个专门关于介绍幻方的博客:http://blog.sina.com.cn/u/1225071715

时间: 2024-09-28 09:57:09

任意阶幻方(魔方矩阵)C语言实现的相关文章

任意阶幻方的c++实现----奇阶幻方、双偶幻方、单偶幻方。

幻方分为3类.奇阶幻方(奇数).双偶幻方(能够被4整除,如8,12,16--).单偶幻方(4m+2形式,如6,10--),构造算法各不相同. 下面的程序中,奇阶幻方的构造算法为Merzirac法.双偶幻方的构造算法为Spring法.单偶幻方的构造算法为Strachey法. 单偶幻方: 在第一行居中的方格内放1,依次向右上方填入2.3.4-,如果右上方已有数字,则向下移一格继续填写. 参考:http://blog.csdn.net/zheng0518/article/details/9006281

任意阶魔方阵(幻方)的算法及C语言实现

写于2012.10: 本来这是谭浩强那本<C程序设计(第四版)>的一道课后习题,刚开始做得时候去网上找最优的算法,结果发现奇数和双偶数(4的倍数)的情况下算法都比较简单,但是单偶数(2的倍数但不是4的倍数)情况一直找不到明确的算法,就连百度百科对这一问题的解释也是“因非四的倍数作法相当复杂,在此只介绍四的倍数的作法”,而且连谭浩强那本书给的答案中竟然也变相的限定了n只能为奇数(题目并未说明).在广泛查找资料后,发现了一篇由中南大学信息科学与工程学院某教授和研究生撰写的论文,介绍了任意阶幻方的算

魔方游戏实现(一):任意阶魔方的表示

 第一节 魔方的简单表示 对于任意N阶的魔方均有六个面(Surface),每个面有N*N个方块.在面向对象的程序设计里,我们可以把魔方(Cube).魔方的面(Surface)和面的方块(Block)均视作为对象. 魔方的定义:六个面存储在一个数组 ''' <summary> ''' 表示一个指定阶的魔方 ''' </summary> Public Class CubeClass ''' <summary> ''' 魔方阶数 ''' </summary> Pu

【C++小白成长撸】--(续)单偶数N阶魔方矩阵

1 /*程序的版权和版本声明部分: 2 **Copyright(c) 2016,电子科技大学本科生 3 **All rights reserved. 4 **文件名:单偶数N阶魔方矩阵 5 **程序作用:单偶数N阶魔方矩阵 6 **作者:Amoshen 7 **完成日期:2016.11.2 8 **版本号:V1.0 9 */ 10 #include<iostream> 11 12 using namespace std; 13 14 #define MAX_SIZE 100 15 16 int

Java 实现任意N阶幻方的构造

一.关于单偶数阶幻方和双偶数阶幻方 (一)单偶数阶幻方(即当n=4k+2时) 任何4k+2 阶幻方都可由2k+1阶幻方与2×2方块复合而成,6是此类型的最小阶. 以6阶为例,可由3阶幻方与由0,1,2,3组成的2×2的小方块拼成一个6×6的大方块复合而成. 其中,3阶幻方(洛书)如下图1所示, (图1) 800x600 Normal 0 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE MicrosoftInternetExplorer4 /* Sty

【C++小白成长撸】--N阶幻方(魔阵)矩阵

解决方法:1.第一个元素放在第一行中间一列 2.下一个元素存放在当前元素的上一行.下一列. 3.如果上一行.下一列已经有内容,则下一个元素的存放位置为当前列的下一行. 在找上一行.下一行或者下一列的时候,必须把这个矩阵看成是回绕的. 代码中,为了判断,当前位置是否有元素,我引入与魔方矩阵规模相同的另一个矩阵,如果魔方矩阵一个位置不为空,相应另一个矩阵那个位置为1,否则为0. 1 /*程序的版权和版本声明部分: 2 **Copyright(c) 2016,电子科技大学本科生 3 **All rig

求N奇数阶幻方

1. 如果矩阵满足条件,那么对任意,也满足条件.证明显然. 设为奇数,我们现在构造一个n阶幻方包含0到所有数这里x,y满足同余式待确定. 由于该方程组的系数矩阵的行列式为1,所以对任意i,j有唯一解.我们接下来确定a,b: 首先验证每行每列的和均相等,即 由于对任意i,,当x取遍模n的剩余类时,也会取遍所有的剩余类 故每行的和为:同理验证每列. 对于对角线:令b = n - 1, a = (n-1)/2,可以验证y = (n - 1)/2, x = i所以其和为:n*(0 + ... n - 1

Java 实现奇数阶幻方的构造

一.设计的流程图如下所示 二.Java 语言的代码实现 package MagicSquare; //奇数幻方的实现 public class Magic_Odd { //n 为幻方的阶数 public static int[][] magicOdd(int n) { //构造一个(n+2)*(n+2)阶的方阵 int[][] square = new int[n + 1][n + 1]; int i = 0; int j = (n + 1) / 2; //从第一行的中间那个数字(是1)开始填幻

小代码3 魔方矩阵

#include <stdio.h> #include <stdlib.h>   #define N 4    //测试所用   void fun() { int a[9][9],r,c,num,n;  //最大9*9的矩阵  可以修改规模 n=N; for(r=0;r<n;r++)   for(c=0;c<n;c++)    a[r][c]=0; r=0;c=n/2;num=1;      a[r][c]=num;             //定位第一个元素 whil