没有题目,之前用剪枝解数独没什么意思,剪枝很生硬,没有任何技巧。这里用了二进制解法,避免了剪枝。
我们用一个九位的二进制数表示某个数字有没有被选过,如(100000000)2 表示 9已经被选过。
我们可以通过位运算看看某个数字过,或将某个数字表示成已选状态。
计算某个数字在哪个九宫格内,只要看看它的横行与纵行对其编号的贡献。
code:
/* 数独二进制解法
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int row[10],cl[10],square[10];
int ans[10][10];
int record[10][10];
bool flag;
void bfs(int r,int c)
{
int t,u;
if(r==10&&c==1)
{
if(flag)for(int i=1;i<=9;++i)
{
for(int j=1;j<=9;++j)
{
cout<<ans[i][j]<<" ";
}
cout<<endl;
}
flag=0;
return ;
}
if(!flag)return ;
if(record[r][c])
{
if(c+1<=9)bfs(r,c+1);
else bfs(r+1,1);
return ;
}
t=((r%3==0?0:1)+r/3-1)*3+((c%3==0?0:1)+c/3);
for(int i=1;i<=9;++i)
{
u=1<<(i-1);
if(u&row[r]||u&cl[c]||u&square[t])continue;
row[r]|=u,cl[c]|=u,square[t]|=u;
ans[r][c]=i;
if(c+1<=9)bfs(r,c+1);
else bfs(r+1,1);
row[r]^=u,cl[c]^=u,square[t]^=u;
ans[r][c]=0;
}
}
int main()
{
memset(row,0,sizeof(row));
memset(cl,0,sizeof(cl));
memset(square,0,sizeof(square));
int t;
for(int i=1;i<=9;++i)
{
for(int j=1;j<=9;++j)
{
scanf("%d",&record[i][j]);
if(record[i][j])
{
ans[i][j]=record[i][j];
row[i]|=(1<<(record[i][j]-1));
cl[j]|=(1<<(record[i][j]-1));
t=((i%3==0?0:1)+i/3-1)*3+((j%3==0?0:1)+j/3);
square[t]|=(1<<(record[i][j]-1));
}
}
}
flag=1;
cout<<"ans: \n";
bfs(1,1);
return 0;
}