看完所有的题解之后发现没有人用二进制,我就知道我的机会来了(手动滑稽)
在做这一题之前你所需要知道的二进制操作
x << y//相当于x * pow(2,y)
lowbit(x)//找到x的二进制中最小的1的位置
1 & 1 = 1
0 & 1 = 0
0 & 0 = 0
//没有了
关于这一题,line,rool,cell三个数组(均初始化为111111111(二进制))分别用来存这一行、列、九宫格(以0开始,方便九宫格的操作)还可以存的数有哪些,存在相对应的二进制位上。
为了得到某一个格子的可以填的数,只需要一个get函数就可以解决。
inline int get(int x,int y){
return line[x]&roll[y]&cell[x/3][y/3];
}
最重要的,注意dfs的顺序(剪枝必备)
就像我们平时做数独一样,从可以填的数最少的格子开始枚举(这一题其实不需要,但是靶形数独一定是要这样剪枝的(可能是强度的问题))
话不多说,上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define _ 0
const int N=9;
int a[N][N];
int line[N],roll[N],cell[N/3][N/3];
int map[1<<N],once[1<<N];//map是为了得到lowbit的对应的位数,once方便找这一格可以填的数的个数
inline void init(){
for(int i=0;i<N;i++)
line[i]=roll[i]=(1<<N)-1;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
cell[i][j]=(1<<N)-1;
}
inline int lowbit(int x){//定义lowbit函数
return x&(-x);
}
inline int get(int x,int y){//定义get函数,前面已经介绍过
return line[x]&roll[y]&cell[x/3][y/3];
}
bool dfs(int cnt){
if(!cnt) return true;
int minn=10;
int x,y;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++){
if(a[i][j]==0)
if(minn>once[get(i,j)]) x=i,y=j,minn=once[get(i,j)];
}//找到可填的数最少的一格
int xx=get(x,y);
for(int i=xx;i;i-=lowbit(i)){
int l=map[lowbit(i)];
a[x][y]=l+1;
line[x] -= 1 << l;
roll[y] -= 1 << l;
cell[x/3][y/3] -= 1 << l;
if(dfs(cnt-1)) return true;
line[x] += 1 << l;
roll[y] += 1 << l;
cell[x/3][y/3] += 1 << l;
a[x][y]=0;
}
return false;
}
int main(){
for(int i=0;i<9;i++){//初始化map
map[1<<i]=i;
}
for(int i=0;i<(1<<N);i++){//初始化once
int s=0;
for(int j=i;j;j-=lowbit(j)){
s++;
}
once[i]=s;
}
init();//初始化line,roll,cell
for(int i=0;i<N;i++)
for(int j=0;j<N;j++){
scanf("%d",&a[i][j]);
}
int cnt=0;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++){
if(!a[i][j]) cnt++;
else{
int t=a[i][j]-1;
line[i]-=1<<t;
roll[j]-=1<<t;
cell[i/3][j/3]-=1<<t;
}
}
dfs(cnt);
for(int i=0;i<N;i++){
for(int j=0;j<N;j++)
printf("%d ",a[i][j]);
putchar('\n');
}
return ~~(0^_^0);//卖个萌
}