#include <bits/stdc++.h>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <unordered_map>
#define xx first
#define yy second
using namespace std;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
typedef long long ll;
const int maxn = 9, maxm = 1 << maxn;
int ones[maxm], ma[maxm];
int row[maxn], col[maxn], cell[3][3];
char str[100];
void init() {
for (int i = 0; i < maxn; i++)
row[i] = col[i] =
(1 << maxn) -
1; //是这些限制里面存的每一位都是1,也就是初始化为0~8为都是1,都可以用。
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) cell[i][j] = (1 << maxn) - 1;
return;
}
void draw(
int x, int y, int t,
bool
is_set) //这里is_set是用来判端是否写入还是擦除:t为该点被选中时,是填入的或者删除的那个数字。
{
if (is_set)
str[x * maxn + y] = '1' + t; //一行九个数字。
else
str[x * maxn + y] = '.';
int v = 1 << t;
if (!is_set) v = -v;
row[x] -= v; //将这个可选项减下去,v为负时则为把这个t的可选项加上。
col[y] -= v;
cell[x / 3][y / 3] -= v;
}
int lowbit(int x) { return x & -x; }
int get(int x, int y) { return row[x] & col[y] & cell[x / 3][y / 3]; }
bool dfs(int cnt) {
if (!cnt) return true; //可行性剪枝
int minv = 10; //每一个格子最多有九种可选项,所以minv取10为初值。
int x, y;
for (int i = 0; i < maxn; i++) {
for (int j = 0; j < maxn; j++) {
if (str[i * maxn + j] == '.') {
int state = get(
i,
j); // state仅仅知识返回一个可以用的01串,ones可以直接得到这个01串中有多少个1,也就是可以选择多少中数字。
if (ones[state] < minv) {
minv = ones[state];
x = i;
y = j;
}
}
}
}
//选择分支数目最少的按个点来改变、、、优化搜索顺序
int state = get(x, y);
// for(int i=state;i;i-=lowbit(i))
// {
// int t=ma[lowbit(i)];
// draw(x,y,t,true);
// if(dfs(cnt-1))return true;//如果可以则不需要其他路径继续走啦,
// 直接一路返回true不跑剩余分支。 draw(x,y,t,false);
// }
while (state) {
int t = ma[lowbit(state)];
draw(x, y, t, true);
if (dfs(cnt - 1)) return true;
draw(x, y, t, false);
state -= lowbit(state);
}
return false;
}
int main() {
for (int i = 0; i < maxn; i++)
ma[1 << i] =
i; //用于接下来直接用这个lowbit数字找到这是2的多少次方等于这个数。
for (int i = 0; i < 1 << maxn; i++) {
for (int j = 0; j < maxn; j++) {
ones[i] += i >> j & 1;
}
}
while (cin >> str, str[0] != 'e') //文件以end结束。
{
init();
int cnt = 0;
for (int i = 0, k = 0; i < maxn; i++) {
for (int j = 0; j < maxn; j++, k++) {
if (str[k] != '.') {
int t = str[k] - '1';
draw(i, j, t, true);
} else
cnt++; //需要递归多少层,draw(1)多少个节点后才能算dfs结束的条件。
}
}
dfs(cnt);
puts(str);
}
return 0;
}
记得之前打过一次美团比赛也是一个数独的题目,图要比一般的图要大,直接输进去答案的题目,当时一脸懵逼,还好大圣厉害给做啦出来减啦20分钟罚时。