数独是一种传统益智游戏,你需要把一个 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
转链接https://www.acwing.com/problem/content/168/
题解:
#include<bits/stdc++.h>
using namespace std;
const int N=9;
//row,col,cell分别存储每一个单元格可以存放的数,将其放到二进制位上,比如一个单元格可以存储123:0000000111
int row[N],col[N],cell[3][3];
//打表内容 ,ones打表0-2^9-1的二进制含有1的个数
int ones[1<<N],Map[1<<N];
char str[100];
//求二进制数的第一个1,inline内联函数,主要用于减少时间
inline int lowbit(int x){
return x&-x;
}
//获取x,y单元格可以选择的数
inline int get (int x,int y){
return row[x]&col[y]&cell[x/3][y/3];
}
void init(){
//row[],col[],cell[][]每一个初始化都应为111111111,即每个数都可选
for(int i=0;i<N;i++)
row[i]=col[i]=(1<<N)-1;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
cell[i][j]=(1<<N)-1;
}
//递归
bool dfs(int cnt){
if(cnt==0)
return true;
int minv=10,x,y;
//获取能填个数最少的单元格
for(int i=0;i<N;i++)
for(int j=0;j<N;j++){
if(str[i*9+j]=='.'){
if(ones[get(i,j)]<minv){
minv=ones[get(i,j)];
x=i,y=j;
}
}
}
for(int i=get(x,y);i>0;i-=lowbit(i)){
int t=Map[lowbit(i)];
str[x*9+y]=t+'1';
row[x]-=1<<t;
col[y]-=1<<t;
cell[x/3][y/3]-=1<<t;
if(dfs(cnt-1)) return true;
row[x]+=1<<t;
col[y]+=1<<t;
cell[x/3][y/3]+=1<<t;
str[x*9+y]='.';
}
return false;
}
int main(){
//map
for(int i=0;i<N;i++)
Map[1<<i]=i;
//打表ones
for(int i=0;i<1<<N;i++){
int s=0;
for(int j=i;j>0;j-=lowbit(j))
s++;
ones[i]=s;
}
//读取数独字符串
while(~scanf("%s",str)&&str[0]!='e'){
//cnt记录需写的个数
int cnt=0;
init();
for(int i=0,k=0;i<N;i++)
for(int j=0;j<N;j++,k++){
if(str[k]!='.'){
int t=str[k]-'1';
row[i]-=1<<t;
col[j]-=1<<t;
cell[i/3][j/3]-=1<<t;
}
else cnt++;
}
dfs(cnt);
cout<<str<<endl;
}
return 0;
}