数独
题目:
- 数独(shù dú)是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。
数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。
求解下面这个数独
问题分析:首先把题目残缺的数独显示出来,用Scanner方法读取控制台的输入,空白处为0,有数字的显示该数字,再写一个print方法打印表格。代码如下:
int[][] board=new int[9][9]; //创建棋盘
Scanner scanner=new Scanner(System.in);
for(int i=0;i<board.length;i++){
String line=scanner.nextLine();
for(int j=0;j<line.length();j++){
board[i][j]=Integer.parseInt(line.charAt(j)+""); //字符+""转字符串,Integer.parseInt转整数
}
}
print(board); //打印棋盘
print函数
public static void print(int[][] board){
for(int i=0;i<board.length;i++){
for(int j=0;j<board[i].length;j++){
System.out.print(board[i][j]+" ");
}
System.out.println();
}
}
接下来是求解数独,写在solve函数中,具体的:从第一行第一列开始,判断该格子空不空,不为空时,即有数字时不管,为空时,要往里填数字,这个数字取值范围0~9,所以循环判断数字是否存在,存在不管,不存在时把这个数字填进去,递归调用solve函数继续填后面的格子,当然我们填进去的数字不一定正确,不正确时,递归不下去,开始回溯,给格子换数字,换数字的前提是该要把该格子的数字删除,所以在换一下个数字前,执行当前格子清空操作。代码实现如下,本程序的核心代码:
private static void solve(int row, int col, int[][] board) {
//写递归先写啥时候结束 到了第十行的时候结束
if(row==9){
print(board);
System.exit(0); //退出程序
}else{
if(board[row][col]==0){ //当前格空时
//该格子可能性1~9,一个格子一个for循环
for(int num=1;num<=9;num++){
if(!isExist(row,col,num,board)){ //该数字不存在时进行赋值操作,并它跳转到下一个格子
board[row][col]=num;
solve(row+(col+1)/9,(col+1)%9,board); //往后递归
}
//递归不下去的时候,把当前这个数字删了,才换一下个数字放
board[row][col]=0;
}
}else{
solve(row+(col+1)/9,(col+1)%9,board); //当前格有数字时,跳到下一个重新执行函数
}
}
}
上面代码中的isExist方法还未实现,判断是否存在,根据数独的游戏规则来,从行,列,小九宫三个方面判断,三情况同时不存在时为false,数字不存在可以放进去。
判断小九宫时比较好理解的方法,根据行和列的最大最小值确定九宫格范围,在这个范围内找该数字存在与否。
代码实现如下:
private static boolean isExist(int row, int col, int num, int[][] board) {
//判断行
for(int c=0;c<9;c++){
if(board[row][c]==num){ //行上存在
return true;
}
}
//判断列
for(int r=0;r<9;r++){
if(board[r][col]==num){ //列上存在
return true;
}
}
//判断小九宫
int rowMin=0;
int rowMax=0;
int colMin=0;
int colMax=0;
if(row>=0&&row<=2){
rowMin=0;
rowMax=2;
}
if(row>=3&&row<=5){
rowMin=3;
rowMax=5;
}
if(row>=6&&row<=8){
rowMin=6;
rowMax=8;
}
if(col>=0&&col<=2){
colMin=0;
colMax=2;
}
if(col>=3&&col<=5){
colMin=3;
colMax=5;
}
if(col>=6&&col<=8){
colMin=6;
colMax=8;
}
for(int r=rowMin;r<=rowMax;r++){
for(int c=colMin;c<=colMax;c++){
if(board[r][c]==num){
return true;
}
}
}
return false;
}
最后整体代码如下:
package 递归;
import java.util.Scanner;
public class Sudoku {
public static void main(String[] args) {
int[][] board=new int[9][9]; //创建棋盘
Scanner scanner=new Scanner(System.in);
for(int i=0;i<board.length;i++){
String line=scanner.nextLine();
for(int j=0;j<line.length();j++){
board[i][j]=Integer.parseInt(line.charAt(j)+""); //字符+""转字符串,Integer.parseInt转整数
}
}
solve(0,0,board);
}
private static void solve(int row, int col, int[][] board) {
//写递归先写啥时候结束 到了第十行的时候结束
if(row==9){
print(board);
System.exit(0); //退出程序
}else{
if(board[row][col]==0){ //当前格空时
//该格子可能性1~9,一个格子一个for循环
for(int num=1;num<=9;num++){
if(!isExist(row,col,num,board)){ //该数字不存在时进行赋值操作,并它跳转到下一个格子
board[row][col]=num;
solve(row+(col+1)/9,(col+1)%9,board); //往后递归
}
//递归不下去的时候,把当前这个数字删了,才换一下个数字放
board[row][col]=0;
}
}else{
solve(row+(col+1)/9,(col+1)%9,board); //当前格有数字时,跳到下一个重新执行函数
}
}
}
private static boolean isExist(int row, int col, int num, int[][] board) {
//判断行
for(int c=0;c<9;c++){
if(board[row][c]==num){ //行上存在
return true;
}
}
//判断列
for(int r=0;r<9;r++){
if(board[r][col]==num){ //列上存在
return true;
}
}
//判断小九宫
int rowMin=0;
int rowMax=0;
int colMin=0;
int colMax=0;
if(row>=0&&row<=2){
rowMin=0;
rowMax=2;
}
if(row>=3&&row<=5){
rowMin=3;
rowMax=5;
}
if(row>=6&&row<=8){
rowMin=6;
rowMax=8;
}
if(col>=0&&col<=2){
colMin=0;
colMax=2;
}
if(col>=3&&col<=5){
colMin=3;
colMax=5;
}
if(col>=6&&col<=8){
colMin=6;
colMax=8;
}
for(int r=rowMin;r<=rowMax;r++){
for(int c=colMin;c<=colMax;c++){
if(board[r][c]==num){
return true;
}
}
}
return false;
}
//打印棋盘函数
public static void print(int[][] board){
for(int i=0;i<board.length;i++){
for(int j=0;j<board[i].length;j++){
System.out.print(board[i][j]+" ");
}
System.out.println();
}
}
}
在控制台输入题目数独求解如下:
005300000
800000020
070010500
400005300
010070006
003200080
060500009
004000030
000009700
1 4 5 3 2 7 6 9 8
8 3 9 6 5 4 1 2 7
6 7 2 9 1 8 5 4 3
4 9 6 1 8 5 3 7 2
2 1 8 4 7 3 9 5 6
7 5 3 2 9 6 4 8 1
3 6 7 5 4 2 8 1 9
9 8 4 7 6 1 2 3 5
5 2 1 8 3 9 7 6 4
进程已结束,退出代码0
当然本程序输入其他残缺数独都可以解出完整的答案。