Sudoku POJ - 3074(數獨+優化搜索順序+位運算優化狀態記錄,檢索和更新)

題意:傳送門
題解:首先考慮一種策略,先填上“已經能夠唯一確定的位置”,然後從那些填的比較滿,選項比較少的位置實施突破。這樣使得搜索樹的規模大大降低,其次考慮的就是在搜索狀態上的記錄,檢索和更新上的開銷(影響程序運行的“常數”時間),可以使用位運算來代替數組執行"對各個位置所填數字的記錄"以及"可填性的檢查與統計",這樣就代替了使得27>127次->1次
算法過程是:

  1. 對於每行每列,每個九宮格,分別用一個99位二進制數保存哪些數字還可以填入。
  2. 對於每個位置,把它所在行、列、九宮格的33個二進制數做&\&運算,得出該位置要填哪些數,用lowbitlowbit運算就可以把能填的數取出。
  3. 優先搜索可填數字少的,當一個位置填上某些數之後,把該位置的行、列、九宮格記錄的二進制數的對應位置改爲00,即可更新狀態,回溯時改爲11恢復現場。

codecode:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=9;
int row[N],col[N],cell[5][5],ones[1<<N],map[1<<N];
char str[100];
inline int lowbit(int x){return x&-x;}
void init()
{
    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;
        }
    }
}
inline 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,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(minv>t){
                    minv=t;x=i;y=j;
                }
            }
        }
    }
    for(int i=get(x,y);i;i-=lowbit(i)){
        int t=map[lowbit(i)];
        row[x]-=(1<<t);
        col[y]-=(1<<t);
        cell[x/3][y/3]-=(1<<t);
        str[x*9+y]='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()
{
    for(int i=0;i<N;i++)map[1<<i]=i;
    for(int i=0;i<1<<N;i++)ones[i]=ones[i>>1]+i%2;
    while(scanf("%s",str),str[0]!='e'){
        init();
        int cnt=0;
        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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章