DFS - POJ 2676 - Sudoku
Sample Input
1
103000509
002109400
000704000
300502006
060000050
700803004
000401000
009205800
804000107
Sample Output
143628579
572139468
986754231
391542786
468917352
725863914
237481695
619275843
854396127
Time limit: 2000 ms
Memory limit: 65536 kB
分析:
具體落實:
代碼:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=9,M=1<<9;
int ones[M],log_2[M];
int row[N],col[N],cell[3][3];
char str[10][10];
void cal()
{
for(int i=0;i<M;i++)
for(int j=0;j<N;j++)
ones[i]+=(i>>j&1);
for(int i=0;i<N;i++) log_2[1<<i]=i;
}
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;
}
void draw(int x,int y,int t,bool is_set)
{
if(is_set) str[x][y]='1'+t;
else str[x][y]='0';
int v=1<<t;
if(!is_set) v=-v; //刪除第t位
row[x]-=v;
col[y]-=v;
cell[x/3][y/3]-=v;
}
int lowbit(int x)
{
return x & -x;
}
int get(int x,int y) //計算(x,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;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
if(str[i][j]=='0')
{
int st=get(i,j);
if(ones[st]<minv)
{
minv=ones[st];
x=i,y=j;
}
}
int st=get(x,y);
for(int i=st;i;i-=lowbit(i))
{
int t=log_2[lowbit(i)];
draw(x,y,t,true);
if(dfs(cnt-1)) return true;
draw(x,y,t,false); //回溯
}
return false;
}
int main()
{
cal();
int T;
cin>>T;
while(T--)
{
Init();
for(int i=0;i<9;i++) cin>>str[i];
int cnt=0; //需要填的數的個數
for(int i=0;i<N;i++) //(i,j)是二維座標,k是一維座標
for(int j=0;j<N;j++)
if(str[i][j]!='0')
{
int t=str[i][j]-'1';
draw(i,j,t,true);
}
else cnt++;
dfs(cnt);
for(int i=0;i<9;i++)
printf("%s\n",str[i]);
}
return 0;
}