zoukankan      html  css  js  c++  java
  • 任意阶幻方(魔方矩阵)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("
    ");
        }
    }
    
    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

  • 相关阅读:
    二叉排序树 常用函数小结
    二叉树的应用:二叉排序树的删除
    剑指 Offer 32
    剑指 Offer 32
    剑指 Offer 68
    剑指 Offer 28. 对称的二叉树 做题小结
    正则表达式不要背
    剑指 Offer 55
    LeetCode226. 翻转二叉树 做题小结
    Tools | 编程IED/编译器
  • 原文地址:https://www.cnblogs.com/ccccnzb/p/4017872.html
Copyright © 2011-2022 走看看