#计算机#数独

数独是一项益智小游戏,规则简单易懂,但内容千变万化。这次我想要研究的是用java编程实现解数独和数独题目的生成。首先要弄清数独的游戏规则:在一个9×9的方格中分布着1-9的数字和空格,玩家在空格中填写适当的数字,使得每行、每列、9个3×3的方格中数字1-9均只出现一次。

对于解数独初步构思的时候我产生了两种想法:

第一种想法利用计算机强大的运算能力,遍历当前空格所有可以填入的数字,向后递归,当某个空格不能填入数字,而空格数不为零时返回上一步。如果某一步只能填入一个确定的数字,可以把这一步优先填好,或者在后续重复经过时直接跳过,来进行优化。

第二种想法是贴近我在填数独时的思路,以3×3的方格为单位,当出现在一行或者一列上的3个方格中有两个出现同一数字,那么第3个数字的行或者列就可以唯一确定。

首先解数独,产生一个可以作为数独完整解的矩阵:

package sudoku;

import java.util.Random;

public class sudoku {

/** 存储数字的数组 */

private static int[][] n = new int[9][9];

/** 生成随机数字的源数组,随机数字从该数组中产生 */

private static int[] num = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

public static int[][] generateShuDu(){

// 生成数字

for (int i = 0; i < 9; i++) {

// 尝试填充的数字次数

int time = 0;

// 填充数字

for (int j = 0; j < 9; j++) {

// 产生数字

n[i][j] = generateNum(time);

// 如果返回值为0,则代表卡住,退回处理

// 退回处理的原则是:如果不是第一列,则先倒退到前一列,否则倒退到前一行的最后一列

if (n[i][j] == 0) {

// 不是第一列,则倒退一列

if (j > 0) {

j -= 2;

continue;

} else {// 是第一列,则倒退到上一行的最后一列

i--;

j = 8;

continue;

}

}

// 填充成功

if (isCorret(i, j)) {

// 初始化time,为下一次填充做准备

time = 0;

} else { // 继续填充

// 次数增加1

time++;

// 继续填充当前格

j--;

}

}

}

return n;

}

/**

* 是否满足行、列和3X3区域不重复的要求

*

* @param row

*            行号

* @param col

*            列号

* @return true代表符合要求

*/

private static boolean isCorret(int row, int col) {

return (checkRow(row) & checkLine(col) & checkNine(row, col));

}

/**

* 检查行是否符合要求

*

* @param row

*            检查的行号

* @return true代表符合要求

*/

private static boolean checkRow(int row) {

for (int j = 0; j < 8; j++) {

if (n[row][j] == 0) {

continue;

}

for (int k = j + 1; k < 9; k++) {

if (n[row][j] == n[row][k]) {

return false;

}

}

}

return true;

}

/**

* 检查列是否符合要求

*

* @param col

*            检查的列号

* @return true代表符合要求

*/

private static boolean checkLine(int col) {

for (int j = 0; j < 8; j++) {

if (n[j][col] == 0) {

continue;

}

for (int k = j + 1; k < 9; k++) {

if (n[j][col] == n[k][col]) {

return false;

}

}

}

return true;

}

/**

* 检查3X3区域是否符合要求

*

* @param row

*            检查的行号

* @param col

*            检查的列号

* @return true代表符合要求

*/

private static boolean checkNine(int row, int col) {

// 获得左上角的坐标

int j = row / 3 * 3;

int k = col / 3 * 3;

// 循环比较

for (int i = 0; i < 8; i++) {

if (n[j + i / 3][k + i % 3] == 0) {

continue;

}

for (int m = i + 1; m < 9; m++) {

if (n[j + i / 3][k + i % 3] == n[j + m / 3][k + m % 3]) {

return false;

}

}

}

return true;

}

/**

* 产生1-9之间的随机数字 规则:生成的随机数字放置在数组8-time下标的位置,随着time的增加,已经尝试过的数字将不会在取到

* 说明:即第一次次是从所有数字中随机,第二次时从前八个数字中随机,依次类推, 这样既保证随机,也不会再重复取已经不符合要求的数字,提高程序的效率

* 这个规则是本算法的核心

*

* @param time

*            填充的次数,0代表第一次填充

* @return

*/

private static Random r=new Random();

private static int generateNum(int time) {

// 第一次尝试时,初始化随机数字源数组

if (time == 0) {

for (int i = 0; i < 9; i++) {

num[i] = i + 1;

}

}

// 第10次填充,表明该位置已经卡住,则返回0,由主程序处理退回

if (time == 9) {

return 0;

}

// 不是第一次填充

// 生成随机数字,该数字是数组的下标,取数组num中该下标对应的数字为随机数字

//      int ranNum = (int) (Math.random() * (9 - time));//j2se

int ranNum=r.nextInt(9 - time);//j2me

// 把数字放置在数组倒数第time个位置,

int temp = num[8 - time];

num[8 - time] = num[ranNum];

num[ranNum] = temp;

// 返回数字

return num[8 - time];

}

public static void main(String[] args) {

int[][] shuDu=generateShuDu();

// 输出结果

for (int i = 0; i < 9; i++) {

for (int j = 0; j < 9; j++) {

System.out.print(shuDu[i][j] + " ");

}

System.out.println();

}

}

}

每次运行都会产生一个数独的完整解,某次运行结果如下:

8 4 1 6 7 5 2 9 3

3 9 6 2 8 1 7 5 4

5 7 2 4 9 3 1 6 8

6 5 8 3 1 9 4 2 7

9 3 7 8 4 2 5 1 6

1 2 4 5 6 7 3 8 9

2 6 3 9 5 4 8 7 1

4 1 9 7 2 8 6 3 5

7 8 5 1 3 6 9 4 2

在这个结果的基础上去掉某些位上的数字,产生一个数独题目。初始数字的数量能够决定题目的难度,至少有17个数字才能保证数独有唯一解。但是在我观察分析题目的时候,并没有发现在去掉完整解中的数字时有什么限制条件,暂且先假定去掉一定数量的任意数字可以形成一个有唯一解的数独题目。在这种情况下只需要产生随机数来挖空这个完整解,就得到了数独题目。

要产生随机数,可以使用Java api中java.lang包中的Math类.Math类以静态方法的方式提供常用的数学方法,其中Math.random()方法是一个可以产生[0.0,1.0]区间内的一个双精度浮点数的方法

如:产生一个100以内的整数:int x=(int)(Math.random()*100);

又如:产生一个1-50之间的随机数:int x=1+(int)(Math.random()*50);

时间: 2024-10-01 20:34:41

#计算机#数独的相关文章

codevs2924 数独挑战

2924 数独挑战 时间限制: 1 s 空间限制: 1000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description “芬兰数学家因卡拉,花费3个月时间设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案.因卡拉说只有思考能力最快.头脑最聪明的人才能破解这个游戏.”这是英国<每日邮报>2012年6月30日的一篇报道.这个号称“世界最难数独”的“超级游戏”,却被扬州一位69岁的农民花三天时间解了出来. 看到这个新闻后,我激动不已,证明我们OI的实力的机会来了,我们虽

数独解法c++实现

转自http://blog.csdn.net/qq_31558353/article/details/50615760 用个小样列(据说是世界上最难的数独,10s过) //<pre code_snippet_id="1592833" snippet_file_name="blog_20160301_1_4048211" name="code" class="cpp">#include <iostream>

解数独算法的实现——剪枝优化

最近人工智能做个小实验,组队选了个数独游戏,顺便研究了一下.解数独感觉主流思想也就是深搜回溯了吧,优化就是各种剪枝方法. 1 引言 数独起源于18世纪初瑞士数学家欧拉等人研究的拉丁方阵(Latin Square),曾风靡日本和英国.现有解法包括基础解法:摒除法,余数法,进阶解法:区块摒除法(Locked Candidates).数组法(Subset).四角对角线(X-Wing).唯一矩形(Unique Rectangle).全双值坟墓(Bivalue Universal Grave).单数链(X

回朔法求数独

你一定听说过"数独"游戏. 如[图1.png],玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个同色九宫内的数字均含1-9,不重复. 数独的答案都是唯一的,所以,多个解也称为无解. 本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目.但对会使用计算机编程的你来说,恐怕易如反掌了. 本题的要求就是输入数独题目,程序输出数独的唯一解.我们保证所有已知数据的格式都是合法的,并且题目有唯一的解. 格式要求,输入9行,每行9个数字,0代表未知

数独问题—题解

你一定听说过"数独"游戏. 如[图1.png],玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个同色九宫内的数字均含1-9,不重复. 数独的答案都是唯一的,所以,多个解也称为无解. 本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目.但对会使用计算机编程的你来说,恐怕易如反掌了. 本题的要求就是输入数独题目,程序输出数独的唯一解.我们保证所有已知数据的格式都是合法的,并且题目有唯一的解. 格式要求,输入9行,每行9个字符,0代表未知

编程的魔力和让计算机开口说话

声明:以下改编自<啊哈C!>一书 先说编程的魔力. 话说起一个数——2147 483 647, 是一个质数,怎么判断它是质数的呢?得感谢我们伟大的欧拉大师,尽管他当时已双目失明,但还是心算出了该数为质数(欧拉在失明后更多产,许多数学相关的论文就在那时候诞生的,说来也奇怪,古今中外能举出很多这样的例子,在遭受痛苦磨难后,仿佛凤凰涅槃,更加焕发生机,例如汉朝的司马迁.德国的贝多芬等).那会儿没发明计算机,欧拉要是穿越到现在来,看到计算机“神机秒算”的功夫,也肯定会对的自己才能感到羞愧,对的,现在计

数独游戏程序

mathe的专栏 http://blog.csdn.net/mathe/article/details/1175498 数独游戏程序 分类: 软件2007-08-23 11:02 22389人阅读 评论(26) 收藏 举报 游戏c图形扩展 数独简介:    数独是一个智力小游戏.一个9*9的棋盘,共有9行9列以及9个互不相交的3*3九宫格.里面某些格子开始已经填上了1-9中的一些数字.要求玩家在余下的空格中填上1-9中数字,使得每行,每列和每个3*3九宫格中都正好包含1-9数字各一个.数独游戏保

【DFS】数独游戏

DFS(深度优先搜索): 深度优先搜索算法(英语:Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法. 沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点.整个进程反复进行直到所有节点都被访问为止.属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n).(一条路走到黑,直到走不下去才往回走) 基本模板: int check(参数) { if(满足条件) return 1;

一种不用递归解决数独问题的思路

过年放假在家,偶然看到老妈在玩数独(Sudoku),想着这完全可以写个程序解决数独问题呀,上网搜了一下大家的思路,发现代码最简单的还是递归算法,不过感觉递归算法有些无脑,运算量又大,想着自己能不能模拟一下人玩数独的思路,让计算机以相对聪明一点点的方式去计算数独的结果呢? 基本思路:对每一行,每一列和每一小九宫格作为一个单元进行分析,共有9*3=27个单元.对于这每一个单元来说,写一个函数need_what来计算一下1-9中还有哪几个数字没有用到,并找出没有填数字的位置坐标.对于每一个没有填数字的