另外一道经典的递归与回溯问题。
数独
背景:
标准数独使用9×9的方格,被划分为9个3×3的宫(称为“粗线宫”)。
数字填充: 需根据已知数字,推理出剩余空格数字,范围限定1-9,且满足:
行唯一: 每行包含1-9不重复
列唯一: 每列包含1-9不重复
宫唯一: 每个3×3宫内包含1-9不重复
解的唯一性: 合格题目仅有一个解。
一个经典的递归问题,
解题思路:
规则:每行1-9,每列1-9,每个正方格1-9不重复。
第一步:
数据规则,创建一个9×9的数组,将已知的数字标注,未知的数字用0代替
确认退出条件:
当整个数组不存在0时,即判定为退出条件
递归条件:判断一个格子 复核放置标准,放置该数字,同时递归调用,寻找下一个为0的格子
参考代码如下:
public class Sudoku {
public static void main(String[] args) {
int[][] board = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 3, 0, 8, 5},
{0, 0, 1, 0, 2, 0, 0, 0, 0},
{0, 0, 0, 5, 0, 7, 0, 0, 0},
{0, 0, 4, 0, 0, 0, 1, 0, 0},
{0, 9, 0, 0, 0, 0, 0, 0, 0},
{5, 0, 0, 0, 0, 0, 0, 7, 3},
{0, 0, 2, 0, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 4, 0, 0, 0, 9}
};
new Sudoku().solution(board);
}
//递归调用方法
public void solution(int[][] board) {
if (exit(board)) {//达成退出条件:打印结果,返回
print(board);
return;
}
//递归条件:遍历格子中所有为0的格子
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 0) {//值为0,需要填补的值
//从1-9中挑选一个数字进行测试
for (int k = 1; k <= 9; k++) {
//测试这个数字是否能放置到该位置
if (isValid(board, i, j, k)) {//有效!
//放置这个数字!
board[i][j] = k;
//递归调用,寻找下一个需要填入的位置:值为0的格子
solution(board);
//回溯时,将这个格子重新调整为0
board[i][j] = 0;//恢复参数
}
}
//1-9都不能解决问题,不能继续填写了,直接返回,向前回溯
return;
}
}
}
}
/**
* 解决方案
*
* @param board 面板
*/
public boolean isValid(int[][] board, int row, int col, int num) {
//每一行的元素不能重复
for (int i = 0; i < board.length; i++) {
if (board[row][i] == num) return false;
}
//每一列的元素不能重复
for (int i = 0; i < board.length; i++) {
if (board[i][col] == num) return false;
}
//每个正方形不能重复
return isBoxValid(board, row, col, num);
}
//判断正方形格子里数值没有重复
public boolean isBoxValid(int[][] board, int row, int col, int num) {
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[startRow + i][startCol + j] == num) {
return false;
}
}
}
return true;
}
/**
* 退出条件,当面板中没有0的时候退出
*
* @param board 面板
* @return 是否退出
*/
public boolean exit(int[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 0) {
return false;
}
}
}
return true;
}
//打印结果
public void print(int[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
System.out.print(" " + board[i][j] + " ");
}
System.out.println("");
}
System.out.println("==============================");
}
}
评论(已关闭)
评论已关闭