You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.8 KiB

2 years ago
#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;
}