Java 递归实现 “5x5魔方阵” 不可行

来源:互联网 发布:网宿科技 阿里云 编辑:程序博客网 时间:2024/05/19 20:59

魔方阵的百科解释:魔方阵,古代又称“纵横图”,是指组成元素为自然数1、2…n2的平方的n×n的方阵,其中每个元素值都不相等,且每行、每列以及主、副对角线上各n个元素之和都相等。

题目:运用java二维数组打印“魔方阵”。所谓魔方阵是指这样的矩阵,它的每一行、每一列和对角线之和均相等,要求打印1~25之间由自然数构成的魔方阵。

这个已经不算什么新问题,当然也不算什么难题,但对于初学者来说,还是有一定难度的。我相信“万能的”度娘已经可以给出让大家满意的答案,但我以一个入门学生的角度来看这一题,当然第一个浮现的方法就是“枚举法”!(最粗暴的办法,毫无技巧可言!)

我个人是这样想的,既然是1~25个数,那么运用高中所学的排列组合知识可以看出,“魔方阵”只是一种特殊的排列情况,那么将所有的排列可能列出,再通过条件筛选出符合“魔方阵”的排列即可(这是我未曾深入了解“魔方阵”的第一个想法,其实这个办法你仔细分析便可得知,时间复杂度非常的大,5X5的组合情况有25!种,再进行条件筛选,工程浩大)。

简单分析下:1~25个数,每行每列对角线和都相等,对角线和列先不考虑,那么每行的和都相等,每一行的和相加就是1+2+3+4+…+25 = 13*25 ,每一行的和就是13*5,同理,每一列的和也为25,对角线也是,那么找到一个排列可能,只需满足此条件即可。

public class MFZ {    //static int cnt = 1;    int[] used = new int[25];//标记数组    int[] mat  = new int[25];//数据数组    int[] num  = new int[25];//存储数组    public MFZ(){        for(int i = 0;i< 25;i++) mat[i] = i+1;//构造方法中使数据1~25录入mat中    }    void magic_cube(int index){        int[][] magic = new int[5][5];//magic魔方阵二维数组        //this.cnt++;        //System.out.print(cnt+"\n");        if(index >= 25) {            int yes = 1;//用于确定数组是否符合条件            int sum ;//用于求和            for(int i = 0;i < 5;i++)                for(int j = 0;j < 5;j++)                    magic[i][j] = num[i*5+j];            //将num复制到魔方中            for(int i = 0; i < 5;i++){                sum = 0;                for(int j = 0;j <5 ;j++){                    sum += magic[i][j];                }                if(sum != 65) {yes = -1;return;}            }            //确定每一行的和是否相等            if(yes==1){                for(int j = 0; j < 5;j++){                    sum = 0;                    for(int i = 0;i <5 ;i++){                        sum += magic[i][j];                    }                    if(sum != 65) {yes = -1;return;}                }            }            //确定每一列的和是否相等            if(yes==1){                if(magic[0][0]+magic[1][1]+magic[2][2]+magic[3][3]+magic[4][4]!=65){ yes = -1;return;}                if(magic[4][0]+magic[3][1]+magic[2][2]+magic[1][3]+magic[0][4]!=65){ yes = -1;return;}            }           //确定对角线的和是否相等            if(yes==1) {//如果都通过,那么打印这个魔方                for(int i = 0;i < 5;i++){                    for(int j = 0;j < 5;j++)                        System.out.print(magic[i][j]+"  ");                    System.out.print("\n");                }                System.out.print("-----------------分割线----------------\n");        }            return;        }        for(int i = 0;i < 25;++i){            if(used[i]==0){//递归体                used[i]=1;                  num[index]=mat[i];//下标应该从0开始到25,因为数组嘛                magic_cube(index+1);                used[i]=0;            }        }    }        public static void main(String[] args) {        // TODO Auto-generated method stub        MFZ a = new MFZ();        a.magic_cube(0);    }}   

其实这种方法理论上是可行的,但是实际上未必可行。因为时间复杂度太大,以上代码中注释行有一个被注释掉的类变量,你可以把这几行代码加进去运行,可以看到MFZ方法一共跑了多少次,当所求矩阵为5X5,eclipse在我的电脑上跑的时候瞬间就跑了300w次,还没跑完!然后我又等了几分钟,还是没跑出来。

跑不出来不代表这个方法不行!我们可以将代码中的25改成9,5改成3,对角线修改一下,那么MFZ方法就变成求“3x3魔方阵”,在我的电脑上瞬间就跑出来了。

其实这并不算一个失败的结果,没错,求“5x5魔方阵”确实失败,但我了解到了即使一个正确的思路,也未必可以得到想要的结果。

其实作为一个初学者,可以看到写出一个让计算机的运算速度捉襟见肘也是一件蛮有趣的事。

1 0