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.

83 lines
3.2 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
int g[N][N]; // 棋盘
// 行,列,九宫格分别用的状态压缩桶
// 索引九宫格是0~8的索引
// 内容值1~9位状态压缩,0位没有用不用管它。
int r[N], c[N], w[N];
bool flag; // 是不是搜索到了第一个答案,如果是,则让其它搜索快速返回,剪一下枝
// 返回九宫格的编号
int get(int x, int y) {
x /= 3, y /= 3; // 注意两个都是/3表示是第几个小方块可以理解为0~8共9个小方块
return x * 3 + y; // 通过上面的变换映射到0~8数字上
}
// x,y这个坐标开始暴搜
// cnt:还有多少个点需要填充
void dfs(int x, int y, 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 nx = x, ny = y + 1; // 下一个位置,默认是向右
if (ny == 9) nx++, ny = 0; // 越界了就从下一行开始
if (g[x][y] == 0) { // 如果此位置是空白
int u = get(x, y); // 这是第几号九宫格
for (int i = 1; i <= 9; i++) { // 尝试填充1~9
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(nx, ny, cnt - 1);
// 恢复状态
r[x] -= 1 << i, c[y] -= 1 << i, w[u] -= 1 << i, g[x][y] = 0;
}
} else // 如果此位置不是空白,那么就尝试下一个位置
dfs(nx, ny, cnt);
}
int main() {
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); // 清空9个小方块的标识
// 找到第一个方案的停止标识
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; // x:行y:列
int u = get(x, y); // 0~8哪个九宫格
g[x][y] = str[i] - '0'; // 棋盘上放上数字
r[x] += 1 << g[x][y]; // 本质上是一个状态压缩,用二进制方式描述 x行上 g[x][y]这个数字的占用情况1表示已使用0表示未使用
c[y] += 1 << g[x][y]; // 列也用状态压缩描述
w[u] += 1 << g[x][y]; // 九宫格也用状态压缩描述
}
// 从左上角暴搜,cnt描述还有多少个位置需要搜索当cnt==0时停止
dfs(0, 0, cnt);
}
return 0;
}