编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
第一次接触回溯算法,道理不难,就是代码比较长
int[][]col=new int[9][10];//记录每一列存在的数
int [][]row=new int[9][10];//记录每一行存在的数
int [][]box=new int[9][10];//记录每一个3*3出现的数
boolean ok=false;//完成数独
//初次遍历,把已有的数记录下来
void solveSudoku(char[][]board)
{
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
if(board[i][j]!='.')
{
int d=Integer.valueOf(board[i][j]+"");
place(board,i,j,d);
}
}
traceback(board, 0, 0);
}
//放置一个数,更新行列框内的值
void place(char[][]board,int i,int j,int d)
{
col[j][d]=1;
row[i][d]=1;
box[(i/3)*3+j/3][d]=1;//得到对应的3*3的框号
board[i][j]=(char)(d+'0');//要加上'0'不然会转成ASCII码对应的字符
}
//回溯算法
void traceback(char[][]board, int i,int j)
{
if(board[i][j]=='.')//对自己填的格子进行回溯
{
for(int k=1;k<10;k++)//从1到9逐个填入看能否满足条件
{
if(couldplace(board,i,j,k))
{
place(board,i,j,k);//放入k值
placenext(board,i,j);/*进行下一个格子的判断,如果一直满足条件,会一直
由此进入下一个格子,直到最后一个格子*/
if(!ok)/*没有达到最后一个格子,但来到这一步,说明出现一次遍历k之后不能找到解,
删除最后放入的格子*/
remove(board, i, j,k);//删除当前格子的值
}
}
}
else placenext(board,i,j);//题目填充好,直接进入放下一个数
}
//能否放置一个数
boolean couldplace(char[][]board,int i,int j,int k)
{
int a=col[j][k]+row[i][k]+box[(i/3)*3+j/3][k];
if(a>0)
return false;
else return true;
}
//放置下一个数,判断是否换行,结束
void placenext(char[][]board,int i,int j)
{
if(i==8&&j==8)//填完
ok=true;
else if(j==8)//换行
traceback(board,i+1,0);
else traceback(board,i, j+1);//下一个
}
//删除该数
void remove(char[][]board,int i,int j,int d)
{
col[j][d]=0;
row[i][d]=0;
box[(i/3)*3+j/3][d]=0;
board[i][j]='.';
}