百科:数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。
如下所示:给定一个空缺的9宫格,完成数独,给出一种结果就好,想要多个结果的(用list集合装,把backTracking函数返回值改为void就好了)
结题思路:
回溯法
从头到尾遍历每个位置,每个位置如果没有数字(本例中对应为0),则在该位置m从1~9开始安放,例如安放1后,开始遍历下个位置n,若失败,则退回位置m,开始安放2,依次类推,典型的回溯思想
package BackTracking;
import java.util.Arrays;
/**回溯算法(难)
* 填充数独
* @author Archerlu
*
*/
public class Sudoku {
public static void main(String[] args) {
int[][] arr = {{5,3,0,0,7,0,0,0,0,},{6,0,0,1,9,5,0,0,0},{0,9,8,0,0,0,0,6,0},
{8,0,0,0,6,0,0,0,3},{4,0,0,8,0,3,0,0,1},{7,0,0,0,2,0,0,0,6},
{0,6,0,0,0,0,2,8,0},{0,0,0,4,1,9,0,0,5},{0,0,0,0,8,0,0,7,9}};
boolean canSudoku = sudokuSovler(arr);
System.out.println(canSudoku);
for(int i=0;i<arr.length;i++) {
System.out.println(Arrays.toString(arr[i]));
}
}
private static boolean sudokuSovler(int[][] arr) {
if(arr==null||arr.length!=9||arr[0].length!=9) return false;
boolean[][] rowFlag = new boolean[9][10]; //指定行row有无数字num(0-9),有的话rowFlag[row][num]=true,
boolean[][] colFlag = new boolean[9][10]; //指定列
boolean[][] cubeFlag = new boolean[9][10];//指定3*3小立方体区域,我是按行读的
for(int i=0;i<9;i++) {
for(int j=0;j<9;j++) {
int num = arr[i][j];
rowFlag[i][num] = true;
colFlag[j][num] = true;
int cubeIndex = i/3*3+j/3;
cubeFlag[cubeIndex][num] = true;
}
}
return backTracking(arr,rowFlag,colFlag,cubeFlag,0,0);
}
private static boolean backTracking(int[][] arr, boolean[][] rowFlag, boolean[][] colFlag, boolean[][] cubeFlag, int m,
int n) {
while(m<9&&arr[m][n]!=0) { //当坐标对应数组元素不为零时,更新坐标
if(n==8) {
m++;
n=0;
}else {
n++;
}
}
if(m==9) return true; //行m==9,说明前9行已经填充完毕,大功告成 返回true
for(int i=1;i<=9;i++) {
if(rowFlag[m][i]||colFlag[n][i]||cubeFlag[(m/3)*3+n/3][i]) continue; //指定行或指定列或指定小立方区域已经有该值i了,弃用i
rowFlag[m][i] = colFlag[n][i] = cubeFlag[m/3*3+n/3][i] = true;
arr[m][n] = i;
if(backTracking(arr,rowFlag,colFlag,cubeFlag,m,n)) {
return true;
}
arr[m][n] = 0;
rowFlag[m][i] = colFlag[n][i] = cubeFlag[m/3*3+n/3][i] = false;
}
return false;
}
}