题目链接:166. 数独 - AcWing题库
标签:dfs
思路:
填每个数时,有三个限制:
1.行约束、2.列约束、3.九宫格约束
每次填数时,先选取一个可选数字最少的位置填,这样可以为其他选择多的位置增加约束,以减少搜索次数。
这里也是用一个二进制数来表示,有多少个数是可以选的,如果第i个位置为1,那么 i 可以被选。
代码:
#include<iostream>
using namespace std;
const int N = 9;
int row[N],col[N],ceil[3][3];//用二进制表示,col[i]的第i位为1表:第i位可以被选
int map[1<<N],ones[1<<N];//map记录i的最低位1位于第几位,ones表示数字i有多少个1(即还有多少数可以被选)
char str[100];
int lowbit(int x)
{
return x & -x;
}
int get(int x,int y)
{
return row[x] & col[y] & ceil[x/3][y/3];
}
bool dfs(int cnt)
{
if(!cnt) return true;
//寻找最少选择的位置
int minv = 10;
int x,y;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(str[i*9+j]=='.')
{
int t = ones[get(i,j)];
if(t<minv)
{
minv=t;
x=i,y=j;
}
}
}
}
//遍历这个位置的所有选择,如果成功返回true
for(int i=get(x,y); i ; i-=lowbit(i))
{
int t = map[lowbit(i)];
row[x] -= 1<<t;
col[y] -= 1<<t;
ceil[x/3][y/3] -= 1<<t;
str[x*N+y] = '1'+t;
if(dfs(cnt-1)) return true;
row[x] += 1<<t;
col[y] += 1<<t;
ceil[x/3][y/3] += 1<<t;
str[x*N+y] = '.';
}
return false;
}
int main()
{
//初始化常数表
for(int i=0;i<N;i++) map[1<<i]=i;
for(int i=0;i<1<<N;i++)
{
for(int j=i;j;j-=lowbit(j)) ones[i]++;
}
while(cin>>str && str[0]!='e')
{
//将所有位置都预置为所有数都可选
for(int i=0;i<N;i++) row[i]= (1<<N) -1;
for(int i=0;i<N;i++) col[i]= (1<<N) -1;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ceil[i][j]=(1<<N) - 1;
//加入输入限制,并记录有多少个位置需要被填充
int cnt = 0;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(str[i*N+j] != '.')
{
int t = str[i*N+j]-'1';
row[i] -= 1<<t;
col[j] -= 1<<t;
ceil[i/3][j/3] -= 1<<t;
}
else cnt++;
}
}
dfs(cnt);
cout<<str<<endl;
}
return 0;
}