1 import java.util.Scanner;
  2 import java.util.Set;
  3 import java.util.TreeSet;
  4 
  5 /*
  6  * 解密9*9数独:
  7  * 格子内填充1-9的数字(空格用0代替),使任意格子的行,列,九宫格都出现1-9的数字
  8  * 注:对于空格较多的数独,遍历层次较深,需要使用更多的栈内存,应适当调节栈内存配置后运行
  9  * 例:
 10  * 8 0 0 0 0 0 0 0 0
 11  * 0 0 3 6 0 0 0 0 0
 12  * 0 7 0 0 9 0 2 0 0
 13  * 0 5 0 0 0 7 0 0 0
 14  * 0 0 0 0 4 5 7 0 0
 15  * 0 0 0 1 0 0 0 3 0
 16  * 0 0 1 0 0 0 0 6 8
 17  * 0 0 8 5 0 0 0 1 0
 18  * 0 9 0 0 0 0 4 0 0
 19  * 结果:
 20  * 8 1 2 7 5 3 6 4 9
 21  * 9 4 3 6 8 2 1 7 5
 22  * 6 7 5 4 9 1 2 8 3
 23  * 1 5 4 2 3 7 8 9 6
 24  * 3 6 9 8 4 5 7 2 1
 25  * 2 8 7 1 6 9 5 3 4
 26  * 5 2 1 9 7 4 3 6 8
 27  * 4 3 8 5 2 6 9 1 7
 28  * 7 9 6 3 1 8 4 5 2
 29  */
 30 public class Main {
 31 
 32     static int[][] source = new int[9][9];//原始数组
 33 
 34     static int[][] target = new int[9][9];//结果数组
 35 
 36     public static void main(String[] args) {
 37         Scanner scanner = new Scanner(System.in);
 38 
 39         /*
 40          * 空格从最上面的行开始,逐行从左向右填充数值
 41          */
 42         Integer firstX = null;//第一个空格的行号
 43         Integer firstY = null;//第一个空格的列号
 44 
 45         /*
 46          * 数组录入输入的数字,并获得第一个空格的行号和列号
 47          */
 48         for(int i=0;i<9;i++){
 49             for(int j=0;j<9;j++){
 50                 int c = scanner.nextInt();
 51                 source[i][j] = c;
 52                 target[i][j] = c;
 53                 if(firstX==null && firstY==null && source[i][j]==0){
 54                     firstX = i;
 55                     firstY = j;
 56                 }
 57             }
 58         }
 59 
 60         //开始遍历填充
 61         go(firstX,firstY);
 62 
 63         //打印结果数组
 64         for(int i=0;i<9;i++){
 65             for(int j=0;j<9;j++){
 66                 System.out.print(target[i][j]+" ");
 67             }
 68             System.out.println("");
 69         }
 70     }
 71 
 72     public static void go(int x,int y){
 73         boolean flag = build(x,y);//填充
 74 
 75         if(flag){//填充成功,获取下一个空格的行号和列号,以源数组为参照
 76             do{
 77                 if(x==8&&y==8){//最后的空格填充完毕,结束填充
 78                     return;
 79                 }
 80                 if(y==8){
 81                     y=0;
 82                     x=x+1;
 83                 }else{
 84                     y=y+1;
 85                 }
 86             }while(source[x][y]!=0);
 87         }else{//填充失败,获取上一个空格的行号和列号,以源数组为参照(因为上一个空格已被填充过,所以需要以源数组作为参照)
 88             do{
 89                 if(x==0&&y==0){//退到第一个空格且无可填充的值,证明无解,结束
 90                     return;
 91                 }
 92                 if(y==0){
 93                     y=8;
 94                     x=x-1;
 95                 }else{
 96                     y=y-1;
 97                 }
 98             }while(source[x][y]!=0);
 99         }
100         /*
101          * 1.如果当前空格填充成功,则填充的是下一个空格
102          * 2.如果当前空格填充失败,则对上一个已填充的空格重新填充
103          */
104         go(x,y);
105     }
106 
107     /*
108      * 1.填充时,优先填充1-9中的较小值
109      * 2.填充时,会有两种情况:1.新空格填充,空格值等于0 2.因后续空格无法继续填充,老空格
110      *   尝试填充新的值,再进行后续空格填充
111      * 3.经过填充后,空格没有获得新值,说明已无合适数字进行填充,需要将空格重置成0,返回f-
112      *   -alse对上一空格进行重新填充
113      * 4.经过填充后,空格获得新值,返回true根据结果判断对后续空格进行填充
114      */
115     public static boolean build(int x,int y){
116         int r = target[x][y];
117         for(int n=r+1;n<10;n++){
118             target[x][y] = n;
119             if(isExists(x,y)){
120                 target[x][y] = r;
121             }else{
122                 break;
123             }
124         }
125         if(target[x][y]==r){
126             target[x][y]=0;//已无可填充数字,将格子重置成0,并重新填充上一个格子
127             return false;
128         }else{
129             return true;
130         }
131     }
132 
133     //判断当前空格的值是否已存在于同行,同列或同九宫格的其他格子中
134     public static boolean isExists(int x,int y){
135         Set<Integer> set = getExists(x,y);
136         return set.contains(target[x][y]);
137     }
138 
139     //获取当前格子的行,列,九宫格中已填充的数字
140     public static Set getExists(int x, int y){
141         Set<Integer> set = new TreeSet<Integer>();
142         for(int i=0;i<9;i++){
143             if(i==x){
144                 continue;
145             }
146             if(target[i][y]==0){
147                 continue;
148             }
149             set.add(target[i][y]);
150         }
151         for(int i=0;i<9;i++){
152             if(i==y){
153                 continue;
154             }
155             if(target[x][i]==0){
156                 continue;
157             }
158             set.add(target[x][i]);
159         }
160         int xn = x/3;
161         int yn = y/3;
162         for(int i=xn*3;i<xn*3+3;i++){
163             for(int j=yn*3;j<yn*3+3;j++){
164                 if(i==x&&j==y){
165                     continue;
166                 }
167                 if(target[i][j]==0){
168                     continue;
169                 }
170                 set.add(target[i][j]);
171             }
172         }
173         return set;
174     }
175 
176 }