MagicSquare Odd(奇数幻方)详解

首先,什么事幻方?

换房这个名字,听起来比较高端,但其实在小学奥数题里就出现过。

一个3*3的方格,让你填数字1~9,使得三个横行三个竖行,以及两条对角线上的数字之和全部相等。

上网上随便一搜,就能找到讲授相关东西的网站。

对于基础的三阶幻方,在几千年前,勤劳朴实的老祖宗们就已经把解法给弄出来了。然而对高阶一点的幻方,则没有一个较为通用的方法。

不过好在我们可以用程序来写出来相关代码。

    public static boolean generateMagicSquare(int n) throws IOException {
        int magic[][] = new int[n][n];
        int row = 0, col = n / 2, i, j, square = n * n;
        for (i = 1; i <= square; i++) {
            magic[row][col] = i;
            if (i % n == 0) row++;
            else {
                if (row == 0) row = n - 1;
                else    row--;
                if (col == (n - 1))
                col = 0;
                else    col++;
            } }
        try(FileWriter filewriter = new FileWriter("D.//1.txt")){
            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++)
                    filewriter.write(magic[i][j] + "\t");
                filewriter.write("\n");
            }
        }

        return true;
    }

嗯,这就是写好的java代码,输入想要得到的幻方阶数n,就会自动给你生成一个n阶的幻方。

但是光看这段代码,肯定是不太容易懂的。秉着对奇数幻方做详解的精神,我就在接下来以五阶幻方为例,过一遍幻方生成的总过程。(为了详解的详,举例的是五阶幻方,而不是最简单的三阶)

(经过注释的代码在文章末尾)

1.首先,将n=5送到幻方函数里,生成5*5的幻方矩阵,行数row设为0,列数col设为5/2=2

我创建了一个txt文件,来模拟一下五阶幻方的创建过程,蓝色高亮的位置magic[0][2]就是我们目前要添加数字的位置。

之后,进入for循环,在magic[2][0]填入1,进行判断,目前的这个i是不是5的倍数啊?如果是的话麻烦您下移一行,到别处玩去。那如果不是,该怎么办呢?您就进入else分支,来对目前的row和col值做一做考察。

首先,你的row值是不是0啊?如果是的话麻溜的到n-1去,否则上移一行;然后,再看看你的col值是多少,是n-1就变到0,不是就+1。我们目前的值是row=0,col=2,在经过这么一通变化之后,就变成了row=4,col=3,这里,就是放数字2的地方。

 看到这里,有的人已经发现了,这个三阶幻方的算法是让放数字的读/写头向右上方移动,要是越过了边界,就从另一边界在迂回过来。没错,这就是这种编程方法的核心了。我们先把数字写到5。

写到5之后,我们发现,这如果再向右上方移动的话,就该把数字1覆盖掉了。这时候我们就明白了为什么要有一个i是不是n的倍数的判定。这个判定的用意就是让读/写头移动到相对位置靠下的斜向行里,如果没有这个判定,程序就只会在最开始的 n个位置上不断覆写。

就比如这样

那么,按照正常程序,幻方应该是被这样一点一点填满的

 

然后彻底填满就是这样。

 程序讲解完了,幻方也没写错,挺好。

但是为什么按照这个算法,就能画出来幻方呢?

为了解释这个问题,我们需要把每个填入的数字分成2部分:令填入数字m=p+q,p与q都是整数,其中p为n的倍数,q为1-n之间的整数。

在这种设定下,

在1-25这些数中,每相邻五个数的的p值相等,而q值分别是1,2,3,4,5,由于取值的限制,p的值较大的数绝对会比p值较小的数要大,不论q的值如何。那么就需要具有相同p值、相同q值的数字处在不同行不同列的位置,譬如排在同一条对角线上(和数独问题有些相似)。不过鉴于幻方要求两条对角线上的元素之和也是相等的,要是将p值相同的数排在一条对角线上的话,这些p值必然是1-n中的中间值,比如在n=5的情况下,p=3.

说到这里,相信大家也都或多或少意识到了,本文给出的幻方搭建方法只是合理情况的一种,而且范围相当的小,仅仅把读/写头移动的方向换成左上,也能在程序正确的情况下画出幻方。

而之前对于p和q值的论述,也只是参照文章给出的计算方法进行分析,这种分析并不具有充分性,譬如下方的矩阵就没有遵守这条规则。

 以上是对文中算法原理的分析。

再贴一下经过我注释的代码。

 public static boolean generateMagicSquare(int n) throws IOException {
        int magic[][] = new int[n][n];               //创建magic二维数组,用于储存magic矩阵
        int row = 0, col = n / 2, i, j, square = n * n;     //根据输入的n来设定常量
        for (i = 1; i <= square; i++) {             //逐次生成magic矩阵里的所有数值
            magic[row][col] = i;                    //从第0行的中间位置开始生成,从1开始,后
                                                                    一个生成的值比前一个大1
            if (i % n == 0) row++;                  //生成好相当于一行数目的值之后就在下一
                                                                   行开始赋值,以免重复赋值
            else {
                if (row == 0) row = n - 1;          //如果row对应第一行,就跳转为最后一行
                else    row--;                      //而如果不是,就将row-1,上移一行
                if (col == (n - 1))                 //对于col同理,只不过增减方向相反
                col = 0;
                else    col++;
            } }
        try(FileWriter filewriter = new FileWriter("src\\P1\\txt\\6.txt")){
            for (i = 0; i < n; i++) {
                for (j = 0; j < n; j++)
                    filewriter.write(magic[i][j] + "\t");
                filewriter.write("\n");
            }
        }

        return true;
    }

然而,在n为偶数的情况下,这个程序会报错,显示数组越界。

为什么n为偶数时程序会报错,如何进行修改,修改后的结果又是怎样的,就在下一篇日志里讲啦。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值