题目:https://www.acwing.com/problem/content/168/
数独是一种传统益智游戏,你需要把一个9 × 9的数独补充完整,使得图中每行、每列、每个3 × 3的九宫格内数字1~9均恰好出现一次。
请编写一个程序填写数独。
输入格式
输入包含多组测试用例。
每个测试用例占一行,包含81个字符,代表数独的81个格内数据(顺序总体由上到下,同行由左到右)。
每个字符都是一个数字(1-9)或一个”.”(表示尚未填充)。
您可以假设输入中的每个谜题都只有一个解决方案。
文件结尾处为包含单词“end”的单行,表示输入结束。
输出格式
每个测试用例,输出一行数据,代表填充完全后的数独。
输入样例:
4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end
输出样例:
417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936
题解:首先考虑每行,每列,每个九宫格的数只能出现一次的限制,我们利用九位的二进制数进行限制,初始为9位都是1,使用的之后的那位变为0,然后,每次先用row[x] & col[y] & cell[x/3][y/3]找到那个点的限制的九位数,利用lowbit运算取出可以用的数,然后我们考虑优化搜索顺序,每次找到可选数字最少的点进行填充(这样可以使搜索分支变少)。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
#define Mst(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&-x
#define x first
#define y second
const int N = 9;
typedef pair<int,int> PII;
string str;
int row[9],col[9],cell[3][3],ones[1<<10];
unordered_map<int,int> mp;
void init() {
rep(i,0,8) {
row[i] = (1<<N)-1;
col[i] = (1<<N)-1;
}
rep(i,0,2) {
rep(j,0,2) {
cell[i][j] = (1<<N)-1;
}
}
}
int get(int x,int y) {
return row[x] & col[y] & cell[x/3][y/3];
}
void dfs(int cnt) {
if(!cnt) {
cout << str << endl;
return;
}
int minn = 10,x,y;
rep(i,0,N-1) {
rep(j,0,N-1) {
if(str[i * N + j] != '.') continue;
int state = get(i,j);
if(minn > ones[state]) {
minn = ones[state];
x = i; y = j;
}
}
}
int state = get(x,y);
for(int i = state;i;i -= lowbit(i)) {
int d = lowbit(i);
int t = mp[lowbit(i)];
row[x] -= d;
col[y] -= d;
cell[x/3][y/3] -= d;
str[x * N + y] = char('1' + t);
dfs(cnt-1);
str[x * N + y] = '.';
row[x] += d;
col[y] += d;
cell[x/3][y/3] += d;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
rep(i,0,8) mp[1<<i] = i;
rep(i,1,1<<N) {
rep(j,0,N-1) {
ones[i] += (i >> j) & 1;
}
}
while(cin >> str && str != "end") {
init();
int len = str.size();
int cnt = 0;
rep(i,0,len-1) {
if(str[i] == '.') {
cnt++;continue;
}
int x = i/9,y = i%9,c = str[i] - '1';
row[x] -= (1<<c);
col[y] -= (1<<c);
cell[x/3][y/3] -= (1<<c);
}
dfs(cnt);
}
return 0;
}