acwing 166 数独(DFS剪枝)

题面

acwing 166 数独(DFS剪枝)_第1张图片

题解

通过位运算表示描绘出当前的局面,某一行某一列某一某一宫格均用1个长度是9为的二进制数表示,若当前位置是1表示该行该列或者该宫格可填入

在选择当前需要填数的位置时,选择分支最少的格子

state = row[x] & col[y] & cell[x / 3][y / 3]表示当前位置(x,y)可填数的状态,某二进制为是1表示可填该数

代码

#include
#include
#include
#include
#include

using namespace std;
const int N=9,M=1<<N;

char str[100];
int row[N],col[N],cell[3][3];  //行列九宫格中数字的状态
int ones[M];   //每个状态1的个数
int map[M];

int lowbit(int x){
    return x&-x;
}

void init(){
    //初始化所有位置都是1(表示可以填任意数字)
    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;
        }
    }
}

void draw(int x,int y,int t,bool is_set){
    if(is_set) str[x*N+y]='1'+t;  //填数字
    else str[x*N+y]='.';  //恢复现场

    //更新状态
    int v=1<<t;
    if(!is_set) v=-v;
    row[x]-=v;
    col[y]-=v;
    cell[x/3][y/3]-=v;
}

//返回可以填哪几个数的二进制状态
int get(int x,int y){
    return row[x]&col[y]&cell[x/3][y/3];
}

bool dfs(int cnt){
    if(!cnt) return true;
    int minv=10;
    int x,y;
    //优先搜索分支少的(1的个数少的)
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(str[i*N+j]=='.'){
                int state=get(i,j);
                if(ones[state]<minv){
                    minv=ones[state];
                    x=i,y=j;
                }
            }
        }
    }
    int state=get(x,y);
    for(int i=state;i;i-=lowbit(i)){
        int t=map[lowbit(i)];
        draw(x,y,t,true);
        if(dfs(cnt-1)) return true;
        draw(x,y,t,false);  //恢复现场
    }
    return false;
}
int main(){

    //预处理一个数是2的多少次方
    for(int i=0;i<N;i++) map[1<<i]=i;
    //预处理每个状态1的个数
    for(int i=0;i<M;i++){
        for(int j=i;j;j-=lowbit(j)){
            ones[i]+=1;
        }
    }

    while(cin>>str,str[0]!='e'){
        init();
        int cnt=0; //有多少个空位置
        int k=0;
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                if(str[k]!='.'){
                    int t=str[k]-'1';
                    draw(i,j,t,true);
                }else{
                    cnt++;
                }
                k++;
            }
        }

        dfs(cnt);
        cout<<str<<endl;
    }

    return 0;
}

你可能感兴趣的:(搜索,dfs,剪枝,二进制)