数独求解
最近几个哥们抱着数独这本书玩起来了,时常拿着数独书上的题目问我,明知道我没玩过数独,还来问我,更为可恨的是,他们问我的是他们已经做出来的,那还问我干嘛,明摆虐我。所以,决心研究一下数独算法,打击一下他们的气焰。
进入正题,下面具体介绍一下数独算法
将数独转化为一个二维矩阵,没填数字的地方值为0
再设计check函数,判断一个数num填到x行y列是否满足数独要求,重点是判断在一个九宫格中是否满足要求,重点代码块如下
// 检查x行y列所在九宫格是否含有数字num
// x/3 * 3, y/3 * 3即可算得x, y所在九宫格开头的数字
for (int i = x / 3 * 3; i <= x / 3 * 3 + 2; i++)
for (int j = y / 3 * 3; j <= y / 3 * 3 + 2; j++) {
if (arr[i][j] == num) {
return false;
}
}
- 最后采用递归,从左到右,依次填入合适数字,
for (int i = 1; i <= 9; i++) {
if (check(x, y, i, arr)) {
arr[x][y] = i;
solveSudoku(x, y + 1, arr);
//必须还原
arr[x][y] = 0;
}
}
一行填完便是列数达到9(列数范围是0-8)就要换另外一行,填完介绍标志便是行数达到9(行数范围是0-8),
具体代码如下
public class TestSudoku {
public static void main(String[] args) {
int[][] arr = {
{ 8, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 3, 6, 0, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 9, 0, 2, 0, 0 },
{ 0, 5, 0, 0, 0, 7, 0, 0, 0 },
{ 0, 0, 0, 0, 4, 5, 7, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 3, 0 },
{ 0, 0, 1, 0, 0, 0, 0, 6, 0 },
{ 0, 0, 8, 5, 0, 0, 0, 1, 0 },
{ 0, 9, 0, 0, 0, 0, 4, 0, 0 }
};
TestSudoku t = new TestSudoku();
t.solveSudoku(0, 0, arr);
}
/**
* 检查x行,y列是否可以填入数字num
*
* @param x
* 代表第x行
* @param y
* 代表第y列
* @param num
* 填入x行y列的数字
* @param arr
* 用来存储数独元素的二维数组
*/
public boolean check(int x, int y, int num, int[][] arr) {
// 检查x行是否存在数字num
for (int j = 0; j < 9; j++) {
if (arr[x][j] == num) {
return false;
}
}
// 检查y列是否存在数字num
for (int i = 0; i < 9; i++) {
if (arr[i][y] == num) {
return false;
}
}
// 检查x行y列所在九宫格是否含有数字num
// x/3 * 3, y/3 * 3即可算得x, y所在九宫格开头的数字
for (int i = x / 3 * 3; i <= x / 3 * 3 + 2; i++)
for (int j = y / 3 * 3; j <= y / 3 * 3 + 2; j++) {
if (arr[i][j] == num) {
return false;
}
}
return true;
}
/**
* 求解数独, 求解大致过程为按行填上合适数字,当一行填满后,再从另外一行开始填,最后一行填完即止
*
* @param x
* x行
* @param y
* y列
* @param arr
* 待求解数独数组
*/
public void solveSudoku(int x, int y, int[][] arr) {
int oldX, oldY;
oldX = x; oldY = y;
//此时求解结束
if (x >= 9) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(arr[i][j]);
}
System.out.println();
}
System.exit(0);
}
//一行填完,再重下行开始填
if (y >= 9) {
solveSudoku(x + 1, 0, arr);
}
//当值为0时,表示此处未填,从1-9数字中选出合适填取
else if (arr[x][y] == 0) {
for (int i = 1; i <= 9; i++) {
//检查填入数字后,是否满足数独要求
if (check(x, y, i, arr)) {
arr[x][y] = i;
solveSudoku(x, y + 1, arr);
//必须还原
arr[x][y] = 0;
}
}
//如果已经填了,向右移一个填上数字
} else {
solveSudoku(x, y + 1, arr);
}
}
}