/*
问题:
1. cell为什么是3 * 3 ,因为一个九宫格就能表示1~9,所以9个九宫格就能表示全部的格子, 那如何确定一个点所属哪个九宫格呢?
x / 3, y / 3, 就可以计算出来了
优化 row[x] & col[y] & cell[x / 3][y / 3] 取交集
ones存的是每个状态有多少个1,即 5 的二进制表示中有 两个 1
map 存的是1对应的位置,eg: (1000)B -> 4, 因为lowbit运算返回的是最后一位1对应的大小,lowbit(10) = 2;
这两个数组相当于以空间换时间,直接查表的作用
*/
import java.io.*;
import java.util.*;
class Main {
static int N = 9;
static int[] ones = new int[1 << 9]; // 求出每个状态中有多少个1
static int[] map = new int[1 << 9];
static int[] row = new int[N], col = new int[N];
static int[][] cell = new int[3][3]; // 问题1
static char[] g = new char[100];
// 初始化
static void init(){
for (int i = 0; i < N; i++) {
row[i] = (1 >> N) - 1;
col[i] = (1 >> N) - 1;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) cell[i][j] = (1 << N) - 1;
}
}
// 在x, y位置上填入数字t, isSet在当前位置是否填入,false表示删除
static void draw(int x, int y, int t, boolean isSet) {
if(isSet) {
g[x * N + y] = (char) ('1' + t); //转换成原来的数字
} else {
g[x * N + y] = '.';
}
int v = 1 << t;
if (!isSet) v = -v;
row[x] -= v;
col[y] -= v;
cell[x / 3][y / 3] -= v;
}
static int lowbit(int x) { // 返回最低位的1
return x & -x;
}
// 可选方案的交集
static int get(int x, int y) { //返回能取哪些数, 000101001, 表示能取第三位和第八位
return row[x] & col[y] & cell[x / 3][y / 3];
}
static boolean dfs(int cnt) {
if (cnt == 0) return true;
// 选择分支最小的格子
int min = 10;
int x = 0, y = 0; // 可选方案数最小的行列坐标
for (int i = 0, k = 0; i < N; i++) {
for (int j = 0; j < N; j++, k++) {
if (g[k] == '.') {
int state = get(i, j); // 能填的数字的交集,
if (ones[state] < min) { // ones[state]有多少个1,就是可选的
min = ones[state];
x = i;
y = j;
}
}
}
}
int state = get(x, y);
for (int i = state; i != 0; i -= lowbit(i)) {
int t = map[lowbit(i)]; // 映射到编号, 编号为2,就表示能填入的数字
draw(x, y, t, true);
if (dfs(cnt - 1)) return true;
draw(x, y, t, false); // 恢复现场
}
return false;
}
public static void main(String[] args) throws IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
for (int i = 0; i < N; i++) map[1 << i] = i;
for (int i = 0; i < 1 << N; i++) {
for (int j = 0; j < N; j++) ones[i] += i >> j & 1;
}
while (true) {
String s = cin.readLine();
if (s.equals("end")) break;
g = s.toCharArray();
init();
int cnt = 0; // 表示当前有多少空位
for(int i = 0, k = 0; i < N; i++) {
for (int j = 0; j < N; j++, k++){
if (g[k] != '.') { // k = i * N + j
int t = g[k] - '1'; // 将数字转为0 ~ 8
draw(i, j, t, true);
} else cnt++;
}
}
dfs(cnt);
System.out.println(new String(g));
}
}
}
问下哪个draw是什么意思?,看不懂里面写的意思