题意:数独。每行、每列、每个九宫格都要有1-9.
关键是要找出怎么通过横纵坐标判断是哪一个子块。
只要推出了公式: k =3* ((i-1)/3)+(j-1)/3+1
i、j、k分别为行、列、块编号,从1开始。
如果从0开始就是k=3*(i/3)+j/3
然后就是dfs的一般写法,如果能放继续搜下一个位置,如果不能就回溯,把标记改回来。
数据比上一个数独 poj 2918要强。。因为不能直接用那个提交啊,会TLE
总结:
1、不能先用scanf读一行。改成cin一个一个的读就AC了。。害我WA了N次。
2、不能一次试探不成功就返回false,应该继续枚举下一个数字。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
bool row[10][10];
bool col[10][10];
bool squ[10][10];
int map[10][10];
bool dfs(int x,int y)
{
if(x==10)
return true;
bool flag=false;
if(map[x][y])
{
if(y==9) flag=dfs(x+1,1);
else flag=dfs(x,y+1);
if(flag) return true;
else return false;
}
else
{
int k=3*((x-1)/3)+(y-1)/3+1;
for(int i=1;i<=9;i++) //从1-9中枚举能放的数
{
if(!row[x][i] && !col[y][i] && !squ[k][i])
{
map[x][y]=i;
row[x][i]=true;
col[y][i]=true;
squ[k][i]=true;
if(y==9) flag=dfs(x+1,1);
else flag=dfs(x,y+1);
if(flag) return true;
else
{
map[x][y]=0;
row[x][i]=false;
col[y][i]=false;
squ[k][i]=false;
//return false; //不能现在就返回,要继续枚举。
}
}
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(row,0,sizeof(row));
memset(col,0,sizeof(col));
memset(squ,0,sizeof(squ));
char t[10][10];
for(int i=1;i<=9;i++)
{
//scanf("%s",t[i]+1);
for(int j=1;j<=9;j++)
{
cin>>t[i][j];
map[i][j]=t[i][j]-'0';
if(map[i][j])
{
int k=3*((i-1)/3)+(j-1)/3+1;
row[i][map[i][j]]=true;
col[j][map[i][j]]=true;
squ[k][map[i][j]]=true;
}
}
}
dfs(1,1);
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
printf("%d",map[i][j]);
printf("\n");
}
}
return 0;
}