题目
解题思路
一、思路说明:
每一个待填的格子中,所能填的数字同时被该格子所在行、列、33块上已有的数字所限制。
如果使用传统方法,在每个代填的格子中遍历每个数时,都得遍历整行、整列、整块,看有没有与该数相同的数字,如果有则不能取该值,没有则选择该值,继续去判断下一个格子。此种方法在同一行、同一列、同一块中重复遍历判断。造成了时间的浪费,非常滴不银杏化。
不妨列三个数组、分别保存该行、列、33块上已经出现过的数字(记为false)和还能填的数字(记为true),判断某个格子能不能填某值时,只需找到该值和坐标对应的行、列、块数组,从三个数组中取出来的值都为true则在该坐标内能填入该数字。
这样做的好处是,同一行判断某个数字能不能填时,不同的格子不用重复遍历所在行、列、块进行判断。
二、数据说明:
利用布尔三个数组保存行、列、块中已经出现过的数字
yFree[n][num]:如果在第n行有num,则为False,否则为True,表示单从行看这一行都可以填入num。
xFree[n][num]:如果在第n列有num,则为False,否则为True,表示单从列看这一列都可以填入num。
blockFree[m][n][num]:如果在第m,n个块里有num,则为False,否则为True。
三、函数与类说明:
1、freeNum类:用来保存三个数组的类。
2、freeNum.isFree(u16 x,u16 y,u16 num):用来判断第y行、x列能否填入num数字,能则返回true。
3、freeNum.setFaulse(u16 x,u16 y,u16 num):将y行、x列的num数字设置成False,有三个作用:
①整个y行都不能再填入num。
②整个x列都不能再填入num。
③整个(x,y)所在的3*3块都不能再填入num。
4、freeNum.setValue(u16 x,u16 y,u16 num):功能与setFaulse相反。用于遍历下个数字时,将上个已遍历的数擦除。
5、giveTortoise(int count);递龟(递归)函数(没错,取名就是这么直白)。用于递归遍历每个格子,将需要填数的格子依次填入可填入的数字,然后递归调用下一个格子。直到最后一个格子有解返回true,如果该格子中没有可填入的数或填入任何数字后级都无解,则返回false,交给前级继续遍历剩下的数。
四、程序说明:
1、初始化FreeNum类的对象。数组所有值幅true。然后遍历已经填好的数,每个已填的数将其所在行、列、块禁填(反应在数据上就是将三个数组对应的位置改成false)。
2、行优先递归每个格子,如果该格子有数则直接递归到下一个数,直到最后一个格子有解,则保存整条递归路径,输出。
代码:
#define u16 unsigned short int
class freeNum
{
public:
bool xFree[9][9]={};
bool yFree[9][9]={};
bool blockFree[3][3][9]={};
freeNum()
{
for(int i=0;i<81;i++)
{
xFree[i%9][i/9]=true;
yFree[i%9][i/9]=true;
blockFree[i/9/3][i/9%3][i%9]=true;
}
}
bool isFree(u16 x,u16 y,u16 num)
{
if(xFree[x][num-1]==true && yFree[y][num-1]==true && blockFree[y/3][x/3][num-1]==true)
{
return true;
}
else return false;
}
void setFalse(u16 x,u16 y,u16 num)
{
//cout<<x<<" "<<y<<" "<<num<<"\n";
xFree[x][num-1] = false;
yFree[y][num-1] = false;
blockFree[y/3][x/3][num-1] = false;
}
void setTrue(u16 x,u16 y,u16 num)
{
xFree[x][num-1] = true;
yFree[y][num-1] = true;
blockFree[y/3][x/3][num-1] = true;
}
};
class Solution {
public:
u16 array[9][9]={0};
freeNum free;
bool giveTortoise(int count)
{
int nowx = count%9;
int nowy = count/9;
if(array[nowy][nowx] != 0)
{
if(count ==80)return true;
else return giveTortoise(count+1);
}
for(int i=1;i<10;i++){
if(free.isFree(nowx,nowy,i))
{
free.setFalse(nowx,nowy,i);
if(count == 80)
{
array[nowy][nowx] = i;
return true;
}
else
{
if(giveTortoise(count+1))
{
array[nowy][nowx] = i;
return true;
}
free.setTrue(nowx,nowy,i);
}
}
}
return false;
}
void solveSudoku(vector<vector<char>>& board) {
for(int y=0;y<9;y++)
{
for(int x=0;x<9;x++)
{
if(board[y][x]=='.')array[y][x]=0;
else
{
array[y][x]=board[y][x]-48;
free.setFalse(x,y,array[y][x]);
}
}
}
giveTortoise(0);
for(int y=0;y<9;y++)
{
for(int x=0;x<9;x++)
{
board[y][x]=array[y][x]+48;
}
}
}
};