用穷举法来求解数独问题。大概思路就是:
1、先挑出以及存在的数字,不作处理。
2、未知数从上到下,从左到右开始枚举,假如第一个数字是[0][0],先假设是1,判断它所在行是否有重复,再判断它所在的列是否有重复,最后判断它所在的9宫格是否有重复。要是都没有重复,就到下一个未知数。如果有重复,就自增。
3、要是自增到10,说明之前的数字有误,就回溯到上一个未知数。
4、要是一行的第一个数字自增到10,就回溯到上一行的最后一个数字。
ps.这种做法感觉好弱智,一些高大上的算法又看不懂。。。
package com.zttech.demo.sudoku;
import static org.hamcrest.CoreMatchers.instanceOf;
import java.io.File;
import java.io.IOException;
import org.junit.Test;
import com.zttech.demo.excel.ExcelOperate;
/**
* 数据求解
* @author guoqicheng
* @date 2018年4月20日
*/
public class Sudoku {
@Test
public void test() throws IOException {
String filePath = "E:\\项目相关\\demo\\sudoku.xlsx";
boolean isExcel2003 = true;
if (ExcelOperate.isExcel2007(filePath)) {
isExcel2003 = false;
}
File file = new File(filePath);
String[][] result = ExcelOperate.getData(file, 0, isExcel2003);
int rowLength = result.length;
for (int i = 0; i < rowLength; i++) {
for (int j = 0; j < result[i].length; j++) {
System.out.print(result[i][j] + "|");
}
System.out.println("\t\t");
}
/** 把从excel读取出来的二维数组转换成int形式的二维数据,未知数用0来表示 */
int[][] arrays = new int[9][9];
for (int i = 0; i < 9; i ++) {
for (int j = 0; j < 9; j++) {
if (result[i][j] == null || "".equals(result[i][j])) {
arrays[i][j] = 0;
} else {
arrays[i][j] = Integer.parseInt(result[i][j]);
}
}
}
System.out.println("-----------------------------------------------");
arrays = calculate(arrays);
for (int i = 0; i < arrays.length; i++) {
for (int j = 0; j < arrays[i].length; j++) {
System.out.print(arrays[i][j] + "|");
}
System.out.println("\t\t");
}
System.out.println("success");
}
/**
* 求解过程
* @param arrays
* @return
*/
public static int[][] calculate(int[][] arrays) {
int count = 0; //步数
//获取已经存在的数字位置
int[][] indexs = getIndex(arrays);
for (int i = 0; i < 9; i ++) {
for (int j = 0; j < 9; j ++) { //遍历整个数组
if (indexs[i][j] != -1) { //如果是未知数
//判断
do {
arrays[i][j] ++;
count++;
} while (!(compareRow(arrays, i, j) && compareCol(arrays, i, j) && compareLattice(arrays, i, j)));
if (arrays[i][j] > 9) {
if (indexs[i][j] != -1) {
arrays[i][j] = 0;
while (j != 0 && indexs[i][j-1] == -1) {
j = j - 1;
}
}
j = j - 2; //回退一步
}
} else {
continue;
}
if (j < -1) {
i = i - 1;
j = 8;
while (indexs[i][j] == -1) {
j = j - 1;
}
j --;
}
}
}
System.out.println(count);
return arrays;
}
/**
* 比较是否和这一行的数字重复
* @param arrays 数组
* @param row 所在的行
* @param col 所在的列
* @return false有重复,true没重复
*/
public static boolean compareRow(int[][] arrays, int row, int col) {
for (int i = col + 1; i < 9; i ++) {
if (arrays[row][col] == arrays[row][i]) {
return false;
}
}
for (int i = col - 1; i >= 0; i --) {
if (arrays[row][col] == arrays[row][i]) {
return false;
}
}
return true;
}
/**
* 比较是否和这一列的数字重复
* @param arrays 数组
* @param row 所在的行
* @param col 所在的列
* @return false有重复,true没重复
*/
public static boolean compareCol(int[][] arrays, int row, int col) {
for (int i = row + 1; i < 9; i ++) {
if (arrays[row][col] == arrays[i][col]) {
return false;
}
}
for (int i = row - 1; i >= 0; i --) {
if (arrays[row][col] == arrays[i][col]) {
return false;
}
}
return true;
}
/**
* 比较是否和九宫格里面的数字重复
* @param arrays 数组
* @param row 所在的行
* @param col 所在的列
* @return false有重复,true没重复
*/
public static boolean compareLattice(int[][] arrays, int row, int col) {
int temp = 0;
for (int k = 0; k <= 8; k += 3) {
for (int l = 0; l <= 8; l += 3) {
if (row >= k && row <= k + 2 && col >= l && col <= l + 2) {
for (int i = k; i <= k + 2; i ++) {
for (int j = l; j <= l + 2; j ++) {
if (arrays[row][col] == arrays[i][j]) {
temp ++; //只能有一次重复(和自己)
}
}
}
}
}
}
if (temp == 1) {
return true;
}else {
return false;
}
}
/**
* 获取以及存在数字的位置
* @param arrays
* @return 如果哪位位置上的值是-1,就代表他是原才存在的
*/
public static int[][] getIndex(int[][] arrays) {
int[][] temp = new int[9][9];
for (int i = 0; i < 9; i ++) {
for (int j = 0; j < 9; j ++) {
if (arrays[i][j] != 0) {
temp[i][j] = -1;
}
}
}
return temp;
}
}