|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int N = 10;
|
|
|
const int M = (1 << 10) + 10; // 2^10 个可能出现的数字
|
|
|
|
|
|
int g[N][N]; // 棋盘
|
|
|
// 行,列,九宫格分别用的状态压缩桶
|
|
|
// 索引:行,列,九宫格是0~8的索引
|
|
|
// 内容值:1~9位,状态压缩,0位没有用,不用管它。
|
|
|
int r[N], c[N], w[N];
|
|
|
bool flag; // 是不是搜索到了第一个答案,如果是,则让其它搜索快速返回,剪一下枝
|
|
|
int one[M]; // 每个0~ 2^10-1 的数字当中,每个数字的二进制表示法中数字1的个数
|
|
|
|
|
|
// 方法1
|
|
|
#define lowbit(x) (x & -x)
|
|
|
int count(int x) {
|
|
|
int cnt = 0;
|
|
|
while (x) x -= lowbit(x), cnt++;
|
|
|
return cnt;
|
|
|
}
|
|
|
|
|
|
// 返回九宫格的编号
|
|
|
int get(int x, int y) {
|
|
|
x /= 3, y /= 3; // 注意两个都是/3,表示是第几个小方块,可以理解为0~8,共9个小方块
|
|
|
return x * 3 + y; // 通过上面的变换,映射到0~8数字上
|
|
|
}
|
|
|
|
|
|
void getPos(int &x, int &y) {
|
|
|
int res = -1; // 每个位置上,已经占用数字最多的是多少个
|
|
|
// 每次通过9*9的双重循环,枚举出每次哪个位置上需要尝试的数字数量是最少的
|
|
|
for (int i = 0; i < 9; i++) {
|
|
|
for (int j = 0; j < 9; j++) {
|
|
|
if (g[i][j]) continue; // 如果已经填充过,就不用理
|
|
|
int u = get(i, j); // 第几个九宫格
|
|
|
int t = r[i] | c[j] | w[u]; // 三者并集生成的数字
|
|
|
if (one[t] > res) { // 这个数字里面的数字1的个数如果大于当前值,修改之。找到1最多的位置
|
|
|
res = one[t]; // 更新个数最大值
|
|
|
x = i, y = j; // 记录当前的坐标
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// cnt:还有多少个点需要填充
|
|
|
void dfs(int cnt) {
|
|
|
if (flag) return; // 快速返回,剪枝
|
|
|
if (cnt == 0) { // 没有空格子了
|
|
|
// 输出答案
|
|
|
for (int i = 0; i < 9; i++)
|
|
|
for (int j = 0; j < 9; j++)
|
|
|
cout << g[i][j];
|
|
|
cout << endl;
|
|
|
// 修改第一次完成的标识
|
|
|
flag = true;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
int x, y; // 记录当前找到的可能性最少的那个点,nx,ny:坐标,nu:哪个九宫格
|
|
|
|
|
|
// 查询获取到最合理的位置作为尝试顺序
|
|
|
getPos(x, y);
|
|
|
|
|
|
// 这是第几个九宫格
|
|
|
int u = get(x, y);
|
|
|
for (int i = 1; i <= 9; i++) {
|
|
|
if (r[x] >> i & 1) continue; // 如果同行出现过,不能填
|
|
|
if (c[y] >> i & 1) continue; // 如果同列出现过,不能填
|
|
|
if (w[u] >> i & 1) continue; // 如果同九宫格出现过,不能填
|
|
|
// 模拟填入
|
|
|
r[x] += 1 << i, c[y] += 1 << i, w[u] += 1 << i, g[x][y] = i;
|
|
|
// 递归下一个位置
|
|
|
dfs(cnt - 1);
|
|
|
// 恢复现场
|
|
|
r[x] -= 1 << i, c[y] -= 1 << i, w[u] -= 1 << i, g[x][y] = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
// 预处理 0~ 2^N 中每个数字二进制表示中数字1的个数
|
|
|
for (int i = 0; i < 1 << N; i++) one[i] = count(i);
|
|
|
|
|
|
string str;
|
|
|
while (cin >> str && str[0] != 'e') {
|
|
|
// 全部清空一次,因为有多组测试数据
|
|
|
memset(g, 0, sizeof g);
|
|
|
memset(r, 0, sizeof r);
|
|
|
memset(c, 0, sizeof c);
|
|
|
memset(w, 0, sizeof w);
|
|
|
// 当前测试数据,还没有找到第一个合理解
|
|
|
flag = false;
|
|
|
|
|
|
int cnt = 0;
|
|
|
for (int i = 0; i < str.size(); i++) {
|
|
|
if (str[i] == '.') {
|
|
|
cnt++;
|
|
|
continue;
|
|
|
}
|
|
|
int x = i / 9, y = i % 9;
|
|
|
int u = get(x, y);
|
|
|
g[x][y] = str[i] - '0';
|
|
|
r[x] += 1 << g[x][y];
|
|
|
c[y] += 1 << g[x][y];
|
|
|
w[u] += 1 << g[x][y];
|
|
|
}
|
|
|
dfs(cnt);
|
|
|
}
|
|
|
return 0;
|
|
|
} |