AcWing 166. 【Java】数独
原题链接
中等
作者:
tt2767
,
2019-12-24 22:44:34
,
所有人可见
,
阅读 972
// 1.dfs 顺序 “选择一个可选答案填入” -> “优先选备选方案少的”
// 2.dfs 状态 “剩余要填几个格子”
// 3.剪枝 3.1 动态选 “优先选备选方案少的”
// 3.2 位运算存状态减少常数
import java.util.*;
public class Main{
void run(){
for (int i = 0 ; i< N ; i++) map[1 << i] = i;
for (int i = 0 ; i < (1 << N) ; i++){
for (int j = i; j > 0; j -= lowBit(j)) {
ones[i]++;
}
}
while (true){
String sd = jin.next();
if (sd.equals("end")) break;
System.out.println(solve(sd));
}
}
int lowBit(int x){
return x & -x;
}
int init(char[] sudoku){
for (int i = 0 ; i < N ; i++){
cell[i] = row[i] = col[i] = (1 << N) - 1;
}
int count = 0;
for (int i = 0 ; i < N; i++){
for (int j = 0 ; j < N ; j++){
if (sudoku[i*N+j] != '.'){
int index = sudoku[i*N+j] - '1';
flip(i, j, 1 << index);
} else {
count ++;
}
}
}
return count;
}
int getStatus(int x, int y){
return row[x] & col[y] & cell[getIndex(x, y)];
}
int getIndex(int x, int y){
return x/3*3 + y/3;
}
void flip(int x, int y, int value){
row[x] ^= value;
col[y] ^= value;
cell[getIndex(x, y)] ^= value;
}
String solve(String sd){
sudoku = sd.toCharArray();
int count = init(sudoku);
dfs(count);
return new String(sudoku);
}
boolean dfs(int count){
if (count == 0) return true;
// 获取备选答案最少的点
int minNumbers = 10;
int x = -1;
int y = -1;
for (int i = 0 ; i < N ; i++){
for (int j = 0 ; j < N ; j++){
if (sudoku[i * N + j] != '.') continue;
int status = getStatus(i,j);
if (status == 0) return false; // 再剪一下
int numbers = ones[status];
if (numbers < minNumbers){
minNumbers = numbers;
x = i;
y = j;
}
}
}
//遍历所有可能
for (int i = getStatus(x, y); i> 0; i -= lowBit(i)){
int candidate = map[lowBit(i)];
int value = 1 << candidate;
flip(x, y, 1 << candidate);
sudoku[x*N+y] = (char)( (char)candidate + '1');
// dfs(count - 1);
if (dfs(count - 1)) return true;
flip(x, y, 1 << candidate);
sudoku[x*N+y] = '.';
}
return false;
}
private int N = 9;
char[] sudoku ;
private int[] row = new int[N];
private int[] col = new int[N];
private int[] cell = new int[N];
private int[] ones = new int[1 << N];
private int[] map = new int[1 << N];
private Scanner jin = new Scanner(System.in);
public static void main(String[] args) throws Exception {new Main().run();}
}