八數碼的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); } }