8数码问题BFS实现---java

    八数码的BFS解法,BFS的优点在于可以找到最优解,但是空间开销大,所要用的时间也会很长,比较好的解法还是加入估价函数搜索的A*和IDA*算法。

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);

   }
}

你可能感兴趣的:(8数码问题BFS实现---java)