八数码的BFS解法,BFS的优势在于能够找到最优解,可是空间开销大,所要用的时间也会很长,比较好的解法仍是加入估价函数搜索的A*和IDA*算法。java
EightPuzzle.java: 算法
package com.satan; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.Stack; import java.util.concurrent.LinkedBlockingDeque; public class EightPuzzle { private String targetState = "123456780";//目标状态 private int[][] targetMatrix = {{1,2,3},{4,5,6},{7,8,0}};//目标矩阵 private Set<String> hashState = new HashSet<String>();//判断状态是否出现 private int[] dx = {-1,0,1,0}; private int[] dy = {0,1,0,-1}; private Map<String, String> path = new HashMap<String, String>(); private int step = 0; /** * 求状态矩阵除去0后的逆序数 * @param Matrix 状态矩阵 * @return 状态矩阵除去0位置的逆序数 */ private int countInverseNumber(int[][] Matrix) { int[] tmpElem = new int[9]; int size = 0; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(Matrix[i][j] != 0) { tmpElem[size++] = Matrix[i][j]; } } } int ans = 0; for(int i = 0; i < size; i++) { for(int j = i+1; j < size; j++) { if(tmpElem[i] > tmpElem[j]) { ans++; } } } return ans; } /** * 判断是否能够由初始的8数码状态到目标状态 * @param startMatrix 初始化8数码的状态矩阵 * @return 是否能够求解 */ private boolean isCanSolve(int[][] startMatrix) { return countInverseNumber(startMatrix) % 2 == countInverseNumber(targetMatrix); } /** * 把存储8数码的矩阵转换为状态字符串 * @param Matrix 8数码存储矩阵 * @return 状态字符串 */ private String convertToStrState(int[][] Matrix) { String string = ""; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { string += Matrix[i][j]; } } return string; } /** * 把状态字符串转换为8数码的矩阵 * @param state 状态字符串 * @return 8数码矩阵 */ private int[][] convertToMatrix(String state) { int[][] matrix = new int[3][3]; for(int i = 0; i < state.length(); i++) { matrix[i/3][i%3] = state.charAt(i) - '0'; } return matrix; } /** * 打印路径 */ private void printPath() { Stack<String> stack = new Stack<String>(); String state = targetState; while(state != null) { stack.push(state); state = path.get(state); step++; } System.out.println("\nOk, I find it!\n"); System.out.println("一共使用了" + (step-1) + "步\n"); while(!stack.isEmpty()) { printMatrix(convertToMatrix(stack.pop())); } } /** * 打印8数码矩阵 * @param matrix 8数码矩阵 */ private void printMatrix(int[][] matrix) { for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { System.out.print(matrix[i][j] + " "); } System.out.println(""); } System.out.println(""); } /** * BFS搜索可行解 * @param startMatrix 开始的8数码矩阵 */ public void searchSolution(int[][] startMatrix) { if(!isCanSolve(startMatrix)) { System.out.println("开始状态到目标状态无解!"); } Queue<String> queue = new LinkedBlockingDeque<String>(); queue.add(convertToStrState(startMatrix));//初始状态放入队列 hashState.add(convertToStrState(startMatrix));//标记初始状态存在 path.put(convertToStrState(startMatrix), null); while(!queue.isEmpty())//队列非空 ,进行BFS { String curState = queue.poll(); int[][] curMatrix = convertToMatrix(curState); if(curState.equals(targetState))//找到目标状态 { break; } int curx = 0, cury = 0; for(int i = 0; i < 3; i++)//查找 0 的位置 { for(int j = 0; j < 3; j++) { if(curMatrix[i][j] == 0) { curx = i; cury = j; break; } } } String newState = "";//记录新状态 int[][] newMatrix = new int[3][3];//记录新状态矩阵 for(int i = 0; i < 4; i++)//BFS 相邻状态 { int newx = curx + dx[i]; int newy = cury + dy[i]; if(newx <= 2 && newx >= 0 && newy <= 2 && newy >= 0)//状态合法 { for(int j = 0; j < 3; j++) { System.arraycopy(curMatrix[j], 0, newMatrix[j], 0, curMatrix[j].length); } int temp = newMatrix[newx][newy]; newMatrix[newx][newy] = newMatrix[curx][cury]; newMatrix[curx][cury] = temp; newState = convertToStrState(newMatrix); if(!hashState.contains(newState))//若是改状态还未到达过 { path.put(newState, curState); queue.add(newState);//把新状态压入队列 hashState.add(newState);//将新状态存入Hash } } } } printPath();//打印路径 } }
EightPuzzleTest.java函数
package com.satan; import java.io.IOException; import java.util.Scanner; public class EightPuzzleTest { public static void main(String[] args) throws IOException, Exception { EightPuzzle eightPuzzle = new EightPuzzle(); int[][] startMatrix = new int[3][3]; Scanner scanner = new Scanner(System.in); for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { startMatrix[i][j] = scanner.nextInt(); } } eightPuzzle.searchSolution(startMatrix); } }