数独简易算法

package cn.tiger.funny;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 计算数独的所有解
 * @author jyuan
 *
 */
public class Sudoku {
	private final Integer[] numbers = {1,2,3,4,5,6,7,8,9};
	private List<Integer[][]> answer = new ArrayList<Integer[][]>();

	/**
	 * 获取数独的所有解
	 * @param squared 数独
	 * @return 数独的所有解
	 */
	public List<Integer[][]> calculate(Integer[][] squared) {
		long start = System.currentTimeMillis();
		startCalculate(squared);
		long end = System.currentTimeMillis();
		System.out.println("take times:" + (end-start) + "ms.");

		print();
		return answer;
	}

	/**
	 * 获得两个数组交集
	 * @param arr1
	 * @param arr2
	 * @return 两个数组交集
	 */
	public Integer[] getB(Integer[] arr1, Integer[] arr2) {
		Set<Integer> set1 = new HashSet<Integer>(Arrays.asList(arr1));
		Set<Integer> set2 = new HashSet<Integer>(Arrays.asList(arr2));
		set1.addAll(set2);
		Integer[] result = {};
		return set1.toArray(result);
	}

	/**
	 * 通过尝试所有可能性获得解
	 * @param squared 数独
	 */
	private void startCalculate(Integer[][] squared) {
		for (int i = 0; i < squared.length; i++) {
			for (int j = 0; j < squared[0].length; j++) {
				if(i == squared.length-1 && j == squared.length-1 && squared[i][j] != 0) {
					Integer[][] copy = new Integer[9][9];
					for (int iLength = 0 ; iLength < 9; iLength++) {
						for (int jLength = 0 ; jLength < 9; jLength++) {
							copy[iLength][jLength] = squared[iLength][jLength];
						}
					}
					answer.add(copy);
				}

				if (squared[i][j] != 0) {
					continue;
				} else {
					for (int number : numbers) {
						if(getUsedInIndex_x(squared, i).contains(number) 
								|| getUsedInIndex_y(squared, j).contains(number) 
								|| getUsedInSquared(squared, i, j).contains(number)) {
							if(number==9) {
								return;
							}
							continue;
						} else {
							squared[i][j] = number;
							startCalculate(squared);
							squared[i][j] = 0;
							if(number==9) {
								return;
							}
						}
					}
				}
			}
		}
	}

	/**
	 * 获得当前小九格中所有存在的数字
	 * @param squared 数独
	 * @param index_x 当前位置的x坐标
	 * @param index_y 当前位置的y坐标
	 * @return 当前小九格中所有存在的数字Set集合
	 */
	private Set<Integer> getUsedInSquared(Integer[][] squared, int index_x, int index_y) {
		int smallSquared = getSmallSquared(index_x, index_y);
		switch (smallSquared) {
		case 1: {
			return getUsedInSquaredVisCore(squared, 1, 1);
		}
		case 2: {
			return getUsedInSquaredVisCore(squared, 1, 4);
		}
		case 3: {
			return getUsedInSquaredVisCore(squared, 1, 7);
		}
		case 4: {
			return getUsedInSquaredVisCore(squared, 4, 1);
		}
		case 5: {
			return getUsedInSquaredVisCore(squared, 4, 4);
		}
		case 6: {
			return getUsedInSquaredVisCore(squared, 4, 7);
		}
		case 7: {
			return getUsedInSquaredVisCore(squared, 7, 1);
		}
		case 8: {
			return getUsedInSquaredVisCore(squared, 7, 4);
		}
		case 9: {
			return getUsedInSquaredVisCore(squared, 7, 7);
		}
		default:
			throw new IllegalArgumentException("Unexpected value: " + smallSquared);
		}
	}

	/**
	 * 获得当前行的所有数字
	 * @param squared 数独
	 * @param index_x 当前位置的x坐标
	 * @return 当前行的所有数字Set集合
	 */
	private Set<Integer> getUsedInIndex_x(Integer[][] squared, int index_x) {
		Set<Integer> usedInIndex_x = new HashSet<Integer>();
		for (int i = 0; i < squared[index_x].length; i++) {
			if (squared[index_x][i] != 0) {
				usedInIndex_x.add(squared[index_x][i]);
			}
		}
		return usedInIndex_x;
	}

	/** 当前列的所有数字
	 * 获得当前列的所有数字
	 * @param squared 数独
	 * @param index_y 当前位置的y坐标
	 * @return 当前列的所有数字Set集合
	 */
	private Set<Integer> getUsedInIndex_y(Integer[][] squared, int index_y) {
		Set<Integer> usedInIndex_y = new HashSet<Integer>();
		for (int i = 0; i < squared.length; i++) {
			if (squared[i][index_y] != 0) {
				usedInIndex_y.add(squared[i][index_y]);
			}
		}
		return usedInIndex_y;
	}

	/**
	 * 获得当前位置的小九格,按1-9排序
	 * @param index_x 当前位置的x坐标
	 * @param index_y 当前位置的y坐标
	 * @return 当前小九格对应的整数
	 */
	private int getSmallSquared(int index_x, int index_y) {
		Integer[] xSquared = getSmallSquaredViaIndex_X(index_x);
		Integer[] ySquared = getSmallSquaredViaIndex_Y(index_y);
		for (int i : xSquared) {
			for (int j : ySquared) {
				if(i == j) {
					return i;
				}
			}
		}
		throw new IllegalArgumentException("Unexpected value: " + index_x + " and " + index_y);
	}

	/**
	 * 获得当前位置对应的一列小九格,小九格按1-9排序
	 * @param index 当前位置的y坐标
	 * @return 返回三个整数数组
	 */
	private Integer[] getSmallSquaredViaIndex_Y(int index) {
		switch (index) {
		case 0:
		case 1:
		case 2: {
			return new Integer[] {1, 4, 7};
		}
		case 3:
		case 4:
		case 5: {
			return new Integer[] {2, 5, 8};
		}
		case 6:
		case 7:
		case 8: {
			return new Integer[] {3, 6, 9};
		}

		default:
			throw new IllegalArgumentException("Unexpected value: " + index);
		}
	}

	/**
	 * 获得当前位置对应的一行小九格,小九格按1-9排序
	 * @param index 当前位置的x坐标
	 * @return 返回三个整数数组
	 */
	private Integer[] getSmallSquaredViaIndex_X(int index) {
		switch (index) {
		case 0:
		case 1:
		case 2: {
			return new Integer[] {1, 2, 3};
		}
		case 3:
		case 4:
		case 5: {
			return new Integer[] {4, 5, 6};
		}
		case 6:
		case 7:
		case 8: {
			return new Integer[] {7, 8, 9};
		}

		default:
			throw new IllegalArgumentException("Unexpected value: " + index);
		}
	}

	/**
	 * 获得当前小九格中所有存在的数字
	 * @param squared 数独
	 * @param index_x 小九格中心位置x坐标
	 * @param index_y 小九格中心位置y坐标
	 * @return
	 */
	private Set<Integer> getUsedInSquaredVisCore(Integer[][] squared, int index_x, int index_y) {
		Set<Integer> usedInSquared = new HashSet<Integer>();	
		for (int i = index_x-1; i <= index_x+1; i++) {
			for (int j = index_y-1; j <= index_y+1; j++) {
				if(squared[i][j] != 0) {
					usedInSquared.add(squared[i][j]);
				}
			}
		}
		return usedInSquared;
	}

	/**
	 * 答应当前数独
	 * @param squared 数独
	 */
	private void print() {
		System.out.println("*********************************************");
		for (Integer[][] squared : answer) {
			System.out.println("------answer------");
			for (int x = 0 ; x < squared.length; x ++) {
				for (int y = 0 ; y < squared[0].length; y++) {
					System.out.print(squared[x][y] + " ");;
				}
				System.out.println();
			}
		}
	}

	public static void main(String[] args) {
		Integer[][] in = new Integer[][] {
			{8, 0, 0, 0, 0, 0, 0, 0, 0},
			{0, 0, 3, 6, 0, 0, 0, 0, 0},
			{0, 7, 0, 0, 9, 0, 2, 0, 0},
			{0, 5, 0, 0, 0, 7, 0, 0, 0},
			{0, 0, 0, 0, 4, 5, 7, 0, 0},
			{0, 0, 0, 1, 0, 0, 0, 3, 0},
			{0, 0, 1, 0, 0, 0, 0, 6, 8},
			{0, 0, 8, 5, 0, 0, 0, 1, 0},
			{0, 9, 0, 0, 0, 0, 4, 0, 0}
		};

		Sudoku sudoku = new Sudoku();
		sudoku.calculate(in);
	}
}

  耗时3257ms. 效率相比之前较低,之前基本可在1s内解决。

posted @ 2020-11-23 11:21  预言2018  阅读(85)  评论(0)    收藏  举报