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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}