数独-- 一个高效率生成数独的算法

先简单的介绍一下数独。来自维基百科的玩法解释:9×9格的大九宫格中有93×3格的小九宫格,并提供一定数量的数字。根据这些数字,利用逻辑和推理,在其它的空格上填入19的数字。每个数字在每个小九宫格内只能出现一次,每个数字在每行、每列也只能出现一次。

那么一共多少个数独矩阵呢?大家可以参看这个链接http://www.afjarvis.staff.shef.ac.uk/sudoku/There are 6670903752021072936960 Sudoku grids (Bertram Felgenhauer and Frazer Jarvis)。这么个数量级,真是吓人,没仔细学习之前我就以为仅有那么几个呢。

最近考研实在是无聊,总是会萌生一些,奇怪的想法,突然看着线性代数就想到了数独矩阵的问题,于是决定试着自己生成几个玩玩。

网上有不少写好的生成算法,我找到的几个大概的实现思路都是现在第一行生成一组1-9不重复的数字,然后第二行开始不停的验证,不停的回退,然后再不停的验证,这种方法有个很好听的名字,叫“回溯法”。如这位大哥http://blog.csdn.net/wallimn/archive/2009/01/14/3775436.aspx,执行一下他给的源代码,效率真是不敢恭维,能不能得出结果了真得看人品。一些提供数独游戏的网站,看他的解释是说,没有做到随机生成,而是当你访问的时候去库里读一个出来给浏览者玩,这种方法也是不可取。如果把这么多个矩阵都存到数据库里去,我勒个去,多大的硬盘?各位看官若有兴趣,请帮忙算一下。于是我在想,如何写一个算法高效率的生成一个数独矩阵呢?

数独的总个数是这么得出来的。9!×722×27× 27,704,267,971=6,670,903,752,021,072,936,960(约有6.67×1021次方)种组合,2005年由Bertram FelgenhauerFrazer Jarvis计算出该数字,如果将重复(如数字交换、对称等)不计算,那么有5,472,730,538个组合。那么有趣的来了,有个9=362880,这个就等于9的全排列,是不是可以从这里做突破口呢?如果我可以随机的生成362880个完整的数独矩阵,然后随机的每行挖去45个那就是362880/24/120*9*362880=411505920个,这个数字够大家有生之年玩的了。

于是我产生了一个看上去比较WS的算法,思路如下,我先写一个数独出来,用二维数组A表示,然后再生成一个乱序的1-9一维数组,用一维数组b表示。遍历这个A数组,在b中找到A数组中当前值所在的位置,然后将b数组中下一个位置的数字赋给A的当前值,目的就是用b数组给A数组中的所有的值,循环的变一下。注意这个b数组的可能性恰好是9的全排列,也就是可以生成362880个数组,也即是生成362880个不同的随机矩阵。我用JAVA实现了我的想法,证明是比较可行,如果你的机器不是上个世纪的古董的话,1秒钟内出一个矩阵是没有问题的。程序里用到的数据矩阵很容易就写出来了,中间的那个九宫格是1-9的顺序排列,第五行第五列都是有规律,然后一个九宫格一个九宫格的填充。

不叨叨,直接上源码:

import java.awt.List; import java.util.ArrayList; import java.util.Random; /** * @author 武鹏 wupeng1003#gmail.com * @version:1.0 * @since 2010年11月21日22:58:43 * @<p>快速生成数独算法</p> * @param args */ public class Sudoku { /** *<p>打印二维数组,数独矩阵 </p> */ public static void printArray(int a[][]) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { System.out.print(" "+a[i][j]); if (0==((j+1)%3)) { System.out.print(" "); } } System.out.println(); if(0==((i+1)%3)) { System.out.println(); } } } /** * <p>产生一个1-9的不重复长度为9的一维数组 </p> */ public static ArrayList<Integer> creatNineRondomArray() { ArrayList <Integer>list = new ArrayList<Integer>(); Random random=new Random(); for (int i = 0; i < 9; i++) { int randomNum=random.nextInt(9)+1; while (true) { if (!list.contains(randomNum)) { list.add(randomNum); break; } randomNum=random.nextInt(9)+1; } } System.out.println("生成的一位数组为:"); for (Integer integer : list) { System.out.print(" "+integer.toString()); } System.out.println(); return list; } /** *<p>通过一维数组和原数组生成随机的数独矩阵</p> *<p> *遍历二维数组里的数据,在一维数组找到当前值的位置,并把一维数组 *当前位置加一处位置的值赋到当前二维数组中。目的就是将一维数组为 *依据,按照随机产生的顺序,将这个9个数据进行循环交换,生成一个随 *机的数独矩阵。 *</p> */ public static void creatSudokuArray(int[][]seedArray,ArrayList<Integer> randomList) { int flag=1; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { for (int k = 0; k < 9; k++) { if(seedArray[i][j]==randomList.get(k)) { seedArray[i][j]=randomList.get((k+1)%9); break; } } } } System.out.println("处理后的数组"); Sudoku.printArray(seedArray); } // public static void main(String[] args) { int seedArray[][]={ {9,7,8,3,1,2,6,4,5}, {3,1,2,6,4,5,9,7,8}, {6,4,5,9,7,8,3,1,2}, {7,8,9,1,2,3,4,5,6}, {1,2,3,4,5,6,7,8,9}, {4,5,6,7,8,9,1,2,3}, {8,9,7,2,3,1,5,6,4}, {2,3,1,5,6,4,8,9,7}, {5,6,4,8,9,7,2,3,1} }; System.out.println("原始的二维数组:"); Sudoku.printArray(seedArray); ArrayList<Integer> randomList=Sudoku.creatNineRondomArray(); Sudoku.creatSudokuArray(seedArray, randomList); } }

后记:经多次测试,出结果是没问题的,但是思路上有点不是太正式的意思,怎么看怎么感觉有点不完美(本人是个轻微的完美主义者),但是效率还是让我很欣慰的。还有,以此思路逆转,是否可以做一个解数独矩阵的算法出来,本人现在缠身的事情真是太多,实在是没时间,请有兴趣有时间的同志们,帮忙实现一下。

希望这个东西能对大家有点帮助,写的不对的地方,请大家给予指正。

转载请注明出处http://blog.csdn.net/peng_wu01/archive/2010/11/22/6026103.aspx,谢谢!交流邮箱wupeng1003#gmail.com。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值