游戏规则:
1、每行都是 1~9
2、没列都是 1~9
3、每块都是 1~9
解答思路:
从坐标 [0][0] 开始,算出其允许填入的数字集合(每行允许数字集合、每列允许数字集合 和 每块允许数字集合 的交集)。
从左到右,从上到下依次尝试(即,递归),当无法向 [下一步] 进行时候,则回溯(恢复状态,再尝试另一个值)。
这样直到最后解答完成。
源代码:
package com.gq.algorithm;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class NumberOnly {
public static Set<Integer> NUMBER = new HashSet<Integer>();
static
{
for( int i=1 ; i<=9 ; i++ )
{
NUMBER.add(i);
}
}
/**
* 记录每行还未输入的数字
*/
private List<Set<Integer>> rowMissNumber = new ArrayList<Set<Integer>>();
/**
* 记录每列还未输入的数字
*/
private List<Set<Integer>> colMissNumber = new ArrayList<Set<Integer>>();
/**
* 记录每方块还未输入的数字
*/
private List<Set<Integer>> squareMissNumber = new ArrayList<Set<Integer>>();
{
for( int i=0 ; i<9 ; i++ )
{
rowMissNumber.add( null );
colMissNumber.add( null );
squareMissNumber.add( null );
}
}
/**
* 解答是否完成
*/
private boolean gameOver = false;
public static void main(String[] args)
{
int[][] numbers = {
{0, 9, 3, 0, 0, 1, 5, 0, 6},
{0, 8, 0, 4, 3, 5, 1, 0, 0},
{0, 0, 7, 9, 0, 2, 0, 8, 4},
{0, 2, 0, 0, 7, 4, 8, 6, 0},
{3, 7, 0, 5, 9, 0, 2, 0, 0},
{9, 0, 4, 1, 0, 8, 7, 5, 0},
{0, 0, 0, 0, 5, 3, 6, 0, 2},
{8, 1, 0, 0, 0, 0, 0, 3, 5},
{6, 0, 0, 0, 1, 9, 0, 0, 8},
};
NumberOnly obj = new NumberOnly();
obj.init(numbers);
obj.solution(0, 0, numbers);
}
/**
* 递归破解
* @param x
* @param y
* @param numbers
*/
void solution( int x, int y, int[][] numbers)
{
if( numbers[x][y] == 0 )
{
Set<Integer> allowNums = possiableNumber(x, y);
for( Integer num : allowNums )
{
numbers[x][y] = num;
// 移除设定的值
rowMissNumber.get(x).remove( num );
colMissNumber.get(y).remove( num );
squareRemove( x,y,num );
// 结束
if( x == 8 && y == 8 )
{
gameOver = true;
print( numbers );
return;
}
// 下一步
int x1=x, y1=0;
if( y == 8 )
{
x1 = (x+1)%9;
}
y1 = (y+1)%9;
solution( x1, y1, numbers);
//如果已经计算完成就不需要再回溯,直接返回
if( gameOver )
{
return;
}
// 恢复
numbers[x][y] = 0;
rowMissNumber.get(x).add( num );
colMissNumber.get(y).add( num );
squareAdd( x, y, num );
}
}
else
{
// 结束
if( x == 8 && y == 8 )
{
gameOver = true;
print( numbers );
return;
}
// 下一步
int x1=x, y1=0;
if( y == 8 )
{
x1 = (x+1)%9;
}
y1 = (y+1)%9;
solution( x1, y1, numbers);
}
}
/**
* 打印结果
* @param numbers
*/
void print( int[][] numbers )
{
if( check(numbers) )
{
System.out.println( "计算数独成功。" );
}
else
{
System.out.println( "计算数独失败。" );
}
for( int i=0 ; i<9 ; i++ )
{
for( int j=0 ; j<9 ; j++ )
{
System.out.print( numbers[i][j] + ", ");
}
System.out.println( );
}
}
/**
* 检查结果是否正确
* @param numbers
* @return
*/
boolean check( int[][] numbers )
{
// 验证每行
for( int i=0 ; i<9 ; i++ )
{
int sum = 0;
for( int j=0 ; j<9 ; j++ )
{
sum += numbers[i][j];
if( j==8 && sum != 45 )
{
return false;
}
}
}
// 验证每列
for( int i=0 ; i<9 ; i++ )
{
int sum = 0;
for( int j=0 ; j<9 ; j++ )
{
sum += numbers[j][i];
if( j==8 && sum != 45 )
{
return false;
}
}
}
// 验证每块
if( !checkSquare(0, 3, 0, 3, numbers))
{
return false;
}
if( !checkSquare(0, 3, 3, 6, numbers))
{
return false;
}
if( !checkSquare(0, 3, 6, 9, numbers))
{
return false;
}
if( !checkSquare(3, 6, 0, 3, numbers))
{
return false;
}
if( !checkSquare(3, 6, 3, 6, numbers))
{
return false;
}
if( !checkSquare(3, 6, 6, 9, numbers))
{
return false;
}
if( !checkSquare(6, 9, 0, 3, numbers))
{
return false;
}
if( !checkSquare(6, 9, 3, 6, numbers))
{
return false;
}
if( !checkSquare(6, 9, 6, 9, numbers))
{
return false;
}
return true;
}
/**
* 验证块
* @param x1
* @param x2
* @param y1
* @param y2
* @param numbers
* @return
*/
boolean checkSquare( int x1, int x2, int y1, int y2, int[][] numbers )
{
int sum =0;
for( int i=x1 ; i<x2 ; i++ )
{
for( int j=y1 ; j<y2 ; j++ )
{
sum += numbers[i][j];
}
}
if( sum != 45 )
{
return false;
}
return true;
}
void squareRemove( int x, int y, int num )
{
if( 0<=x && x <=2 )
{
if( 0<=y && y<=2 )
{
squareMissNumber.get(0).remove( num );
}
if( 3<=y && y<=5 )
{
squareMissNumber.get(1).remove( num );
}
if( 6<=y && y<=8 )
{
squareMissNumber.get(2).remove( num );
}
}
if( 3<=x && x <=5 )
{
if( 0<=y && y<=2 )
{
squareMissNumber.get(3).remove( num );
}
if( 3<=y && y<=5 )
{
squareMissNumber.get(4).remove( num );
}
if( 6<=y && y<=8 )
{
squareMissNumber.get(5).remove( num );
}
}
if( 6<=x && x <=8 )
{
if( 0<=y && y<=2 )
{
squareMissNumber.get(6).remove( num );
}
if( 3<=y && y<=5 )
{
squareMissNumber.get(7).remove( num );
}
if( 6<=y && y<=8 )
{
squareMissNumber.get(8).remove( num );
}
}
}
void squareAdd( int x, int y, int num )
{
if( 0<=x && x <=2 )
{
if( 0<=y && y<=2 )
{
squareMissNumber.get(0).add( num );
}
if( 3<=y && y<=5 )
{
squareMissNumber.get(1).add( num );
}
if( 6<=y && y<=8 )
{
squareMissNumber.get(2).add( num );
}
}
if( 3<=x && x <=5 )
{
if( 0<=y && y<=2 )
{
squareMissNumber.get(3).add( num );
}
if( 3<=y && y<=5 )
{
squareMissNumber.get(4).add( num );
}
if( 6<=y && y<=8 )
{
squareMissNumber.get(5).add( num );
}
}
if( 6<=x && x <=8 )
{
if( 0<=y && y<=2 )
{
squareMissNumber.get(6).add( num );
}
if( 3<=y && y<=5 )
{
squareMissNumber.get(7).add( num );
}
if( 6<=y && y<=8 )
{
squareMissNumber.get(8).add( num );
}
}
}
/**
* 计算出指定坐标可能输入的数字
* @return
*/
Set<Integer> possiableNumber( int x, int y )
{
Set<Integer> result = buildAllNumber();
result.retainAll( rowMissNumber.get(x) );
result.retainAll( colMissNumber.get(y) );
if( 0<=x && x <=2 )
{
if( 0<=y && y<=2 )
{
result.retainAll( squareMissNumber.get(0) );
}
if( 3<=y && y<=5 )
{
result.retainAll( squareMissNumber.get(1) );
}
if( 6<=y && y<=8 )
{
result.retainAll( squareMissNumber.get(2) );
}
}
if( 3<=x && x <=5 )
{
if( 0<=y && y<=2 )
{
result.retainAll( squareMissNumber.get(3) );
}
if( 3<=y && y<=5 )
{
result.retainAll( squareMissNumber.get(4) );
}
if( 6<=y && y<=8 )
{
result.retainAll( squareMissNumber.get(5) );
}
}
if( 6<=x && x <=8 )
{
if( 0<=y && y<=2 )
{
result.retainAll( squareMissNumber.get(6) );
}
if( 3<=y && y<=5 )
{
result.retainAll( squareMissNumber.get(7) );
}
if( 6<=y && y<=8 )
{
result.retainAll( squareMissNumber.get(8) );
}
}
return result;
}
/**
* 初始化
* @param numbers
*/
void init( int[][] numbers )
{
for( int i=0 ; i<9 ; i++ )
{
for( int j=0 ; j<9 ; j++ )
{
// 初始化行
if( rowMissNumber.get(i) == null )
{
rowMissNumber.set(i, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
rowMissNumber.get(i).remove( numbers[i][j] );
}
// 初始化列
if( colMissNumber.get(j) == null )
{
colMissNumber.set(j, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
colMissNumber.get(j).remove( numbers[i][j] );
}
// 初始化方块
//[0][0] ~ [2][2]
if( 0<=i && i <=2 )
{
if( 0<=j && j<=2 )
{
if( squareMissNumber.get(0) == null )
{
squareMissNumber.set(0, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(0).remove( numbers[i][j] );
}
}
if( 3<=j && j<=5 )
{
if( squareMissNumber.get(1) == null )
{
squareMissNumber.set(1, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(1).remove( numbers[i][j] );
}
}
if( 6<=j && j<=8 )
{
if( squareMissNumber.get(2) == null )
{
squareMissNumber.set(2, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(2).remove( numbers[i][j] );
}
}
}
if( 3<=i && i <=5 )
{
if( 0<=j && j<=2 )
{
if( squareMissNumber.get(3) == null )
{
squareMissNumber.set(3, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(3).remove( numbers[i][j] );
}
}
if( 3<=j && j<=5 )
{
if( squareMissNumber.get(4) == null )
{
squareMissNumber.set(4, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(4).remove( numbers[i][j] );
}
}
if( 6<=j && j<=8 )
{
if( squareMissNumber.get(5) == null )
{
squareMissNumber.set(5, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(5).remove( numbers[i][j] );
}
}
}
if( 6<=i && i <=8 )
{
if( 0<=j && j<=2 )
{
if( squareMissNumber.get(6) == null )
{
squareMissNumber.set(6, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(6).remove( numbers[i][j] );
}
}
if( 3<=j && j<=5 )
{
if( squareMissNumber.get(7) == null )
{
squareMissNumber.set(7, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(7).remove( numbers[i][j] );
}
}
if( 6<=j && j<=8 )
{
if( squareMissNumber.get(8) == null )
{
squareMissNumber.set(8, buildAllNumber());
}
if( numbers[i][j] != 0 )
{
squareMissNumber.get(8).remove( numbers[i][j] );
}
}
}
}
}
}
/**
* 构造一个集合,包含1~9
* @return
*/
Set<Integer> buildAllNumber()
{
Set<Integer> set = new HashSet<Integer>();
for( int i=1 ; i<=9 ; i++ )
{
set.add(i);
}
return set;
}
}
int[][] numbers = {
{5, 0, 6, 0, 0, 0, 0, 8, 0},
{0, 4, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 5, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 6, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 3, 0, 0},
{0, 0, 0, 0, 0, 0, 9, 0, 8}
};
int[][] numbers = {
{4, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0, 0},
{0, 5, 0, 0, 0, 0, 0, 7, 0},
{0, 8, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 6, 0, 1, 0},
{0, 6, 0, 0, 0, 0, 0, 5, 0}
};
int[][] numbers = {
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
};