数独是一个很有意思的游戏,我以前玩过很多次,但一直没想过自己写一个。
读《编程之美》在构造数独这一小节中,书中给我们两个算法,这两个算法都是用来初步生成一张初始的数独图。
回溯法和置换法。
对于第二个置换法,真的是超级简单,我看的时候简直惊呆了,还有这种操作,能这么简单。
简单讲一些两个算法:
回溯法:从第一个格子开始,在1-9数字中找一个合适放进去,然后下一个格子,再从1-9找合适的数字放进去,这时候要检验,检验这个格子中的数组是否和行,列,3*3小矩阵中数字有重复,如果找了一圈没找到合适的,就执行回溯,也就是回到上一个格子,把上一个格子里的数字换掉,然后再进行操作。这种操作方式对于学了算法的程序员来讲很容易想到。
置换法:先设置一个3*3矩阵。然后...
图中的{a,b,c,d,e,f,g,h,i}可以随机映射为{1,2,3,4,5,6,7,8,9},可以生成9!个不同的数独,但这不是所有的。
但是这种算法确实超级简单的。
关于实现:
public class Sudoku {
//回溯法
public static void main(String[] args) {
// TODO Auto-generated method stub
Sudoku s = new Sudoku();
s.sudoku();
}
public void sudoku(){
int i,j;
int[][] sudoku = new int[9][9];
sudoku = init(sudoku);
//回溯法
int k ;
k = 0;
while (true){
i = k / 9;
j = k % 9;
while (true){
sudoku[i][j]++;
if (sudoku[i][j] == 10){
//全部测试一遍,失败,返回上一格
sudoku[i][j] = 0;
--k;
break;
}else if (check(sudoku,i,j)){
//成功,下一格
++k;
break;
}
}
if (k == 81){
outSudoku(sudoku);
return;
}
}
}
private int[][] init(int[][] sudoku){
int i;
int j;
int temp;
for (i = 0; i < 9; i++){
for (j = 0 ; j < 9 ; j++){
sudoku[i][j] = 0;
}
}
for (i = 0 ; i < 9 ;i++){
temp = (int)(Math.random()*81);
sudoku[temp/9][temp%9] = i + 1;
}
return sudoku;
}
//检测这个值是否满足要求
private boolean check(int[][] sudoku, int i, int j){
int value = sudoku[i][j];
int p, q;
int m, n;
//检测行中有没有与之重复数值,有 则返回false
for (p = 0; p < 9; p++)
if (p != i && sudoku[p][j] == value)
return false;
//检测列中有没有与之重复的数值,有 则返回false
for (p = 0; p < 9; p++)
if (p !=j && sudoku[i][p] == value)
return false;
p = i/3;
q = j/3;
//检测3*3 小矩阵
for (m = p*3; m < p*3+3; m++)
for (n = q*3; n < q*3+3; n++)
if (m != i && n != j && sudoku[m][n] == value)
return false;
return true;
}
//输出数独数组
private void outSudoku(int[][] sudoku){
int i;
int j;
for (i = 0; i < 9; i++){
for (j = 0; j < 9 ; j++){
System.out.print(sudoku[i][j] + " ");
}
System.out.println();
}
}
}
我参考http://blog.csdn.net/hustspy1990/article/details/7464698他的写了一版java的回溯法。
对于第二种算法置换法的数据结构,我想不直接用二维数组,而是用对象,一个对象代表一个3*3的小矩阵,这样写起来可能不会更易理解。【待验证】