算法学习之8数码问题

  这几天都在写人工智能和信息安全作业,没怎么学算法书,不过现在上的课也多多少少在学算法相关的,这次实验,我们人工智能老师就是要求我们解决八数码问题。

首先我们要知道什么是八数码问题:

  八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。

8 5 4
3   7
1 2 6

(a) 初始状态

1 2 3
8   4
7 6 5


(b) 目标状态  

要求:请任选一种盲目搜索算法(深度优先搜索或宽度优先搜索)或 任选一种启发式搜索方法(A 算法或 A* 算法)编程求解八数码问题(初始状态任选),并对实验结果进行分析,得出合理的结论。

  这里我为了简单点用的bfs(宽度优先搜索),首先给出矩阵后为了方便处理(标记是否出现过)转为一维字符串形式,

/**
    * 把存储8数码的矩阵转换为状态字符串
    * @param Matrix 8数码存储矩阵
    * 状态字符串
    */
   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 startMatrix 初始化8数码的状态矩阵
    * 是否可以求解
    */
   private boolean isCanSolve(int[][] startMatrix)
   {
       
//       System.out.println(countInverseNumber(startMatrix));
//       System.out.println(countInverseNumber(targetMatrix));
       if(countInverseNumber(startMatrix)%2==1&&countInverseNumber(targetMatrix)%2==1)return true;
       else return false;
   }

如果有解,就开始BFS了,首先把初始状态矩阵放入队列中(这里为了处理方便先把矩阵转为状态字符串再放入的队列),然后循环弹出队列,直到队列为空。【每弹出一个矩阵状态字符串,就把这个矩阵的子矩阵状态的状态字符串放入队列中,矩阵的子矩阵状态就是当前矩阵把0与上、下、左、右、四个位置的数(如果有的话)互换后的矩阵。在放子矩阵状态字符串到队列的时候还要先判断下这个矩阵是否重复出现过。】

全部代码吧。

  1 package gh;
  2 
  3 import java.io.IOException;
  4 import java.util.HashMap;
  5 import java.util.HashSet;
  6 import java.util.Map;
  7 import java.util.Queue;
  8 import java.util.Scanner;
  9 import java.util.Set;
 10 import java.util.Stack;
 11 import java.util.concurrent.LinkedBlockingDeque;
 12  
 13  /**
 14   * 八数码问题
 15   * @author ganhang
 16   *
 17   */
 18 public class EightPuzzle
 19 {
 20    private String targetState = "123804765";//目标状态
 21    private int[][] targetMatrix = {{1,2,3},{8,0,4},{7,6,5}};//目标矩阵
 22    private Set<String> hashState = new HashSet<String>();//判断状态是否出现
 23    private int[] dx = {-1,0,1,0};
 24    private int[] dy = {0,1,0,-1};
 25    private Map<String, String> path = new HashMap<String, String>();
 26    private int step = 0;
 27    public static void main(String[] args) throws IOException, Exception {
 28         EightPuzzle eightPuzzle = new EightPuzzle();
 29         int[][] startMatrix = new int[3][3];
 30         Scanner scanner = new Scanner(System.in);
 31         System.out.println("请输入初始状态:");
 32         for (int i = 0; i < 3; i++) {
 33             for (int j = 0; j < 3; j++) {
 34                 startMatrix[i][j] = scanner.nextInt();
 35             }
 36         }
 37 
 38         eightPuzzle.searchSolution(startMatrix);
 39 
 40     }
 41    /**
 42     * 求状态矩阵除去0后的逆序数
 43     * @param Matrix 状态矩阵
 44     * 
 45     */
 46    private int countInverseNumber(int[][] Matrix)
 47    {
 48        int[] tmpElem = new int[9];
 49        int size = 0;
 50        for(int i = 0; i < 3; i++)
 51        {
 52            for(int j = 0; j < 3; j++)
 53            {
 54                if(Matrix[i][j] != 0)
 55                {
 56                    tmpElem[size++] = Matrix[i][j];
 57                }
 58            }
 59        }
 60        int ans = 0;
 61        for(int i = 0; i < size; i++)
 62        {
 63            for(int j = i+1; j < size; j++)
 64            {
 65                if(tmpElem[i] > tmpElem[j])
 66                {
 67                    ans++;
 68                }
 69            }
 70        }
 71        return ans;
 72    }
 73     
 74    /**
 75     * 判断是否可以由初始的8数码状态到目标状态
 76     * @param startMatrix 初始化8数码的状态矩阵
 77     * 是否可以求解
 78     */
 79    private boolean isCanSolve(int[][] startMatrix)
 80    {
 81        
 82 //       System.out.println(countInverseNumber(startMatrix));
 83 //       System.out.println(countInverseNumber(targetMatrix));
 84        if(countInverseNumber(startMatrix)%2==1&&countInverseNumber(targetMatrix)%2==1)return true;
 85        else return false;
 86    }
 87     
 88    /**
 89     * 把存储8数码的矩阵转换为状态字符串
 90     * @param Matrix 8数码存储矩阵
 91     * 状态字符串
 92     */
 93    private String convertToStrState(int[][] Matrix)
 94    {
 95        String string = "";
 96        for(int i = 0; i < 3; i++)
 97        {
 98            for(int j = 0; j < 3; j++)
 99            {
100                string += Matrix[i][j];
101            }
102        }
103        return string;
104    }
105    /**
106     * 把状态字符串转换为8数码的矩阵
107     * @param state 状态字符串
108     *8数码矩阵
109     */
110    private int[][] convertToMatrix(String state)
111    {
112        int[][] matrix = new int[3][3];
113        for(int i = 0; i < state.length(); i++)
114        {
115            matrix[i/3][i%3] = state.charAt(i) - '0';
116        }
117        return matrix;
118    }
119     
120    /**
121     * 打印路径
122     */
123    private void printPath()
124    {
125  
126        Stack<String> stack = new Stack<String>();
127        String state = targetState; 
128        while(state != null)
129        {
130            stack.push(state);
131            state = path.get(state);
132            step++;
133        }
134        System.out.println("\nOk, I find it!\n");
135        System.out.println("一共使用了" + (step-1) + "步\n");
136        while(!stack.isEmpty())
137        {
138            printMatrix(convertToMatrix(stack.pop()));
139        }
140    }
141     
142    /**
143     * 打印8数码矩阵
144     * @param matrix 8数码矩阵
145     */
146    private void printMatrix(int[][] matrix)
147    {
148        for(int i = 0; i < 3; i++)
149        {
150            for(int j = 0; j < 3; j++)
151            {
152                System.out.print(matrix[i][j] + " ");
153            }
154            System.out.println("");
155        }
156        System.out.println("");
157    }
158     
159    /**
160     * BFS搜索可行解
161     * @param startMatrix 开始的8数码矩阵
162     */
163    public void searchSolution(int[][] startMatrix)
164  {
165         if (!isCanSolve(startMatrix)) System.out.println("开始状态到目标状态无解!");
166         else {
167             Queue<String> queue = new LinkedBlockingDeque<String>();
168 
169             queue.add(convertToStrState(startMatrix));// 初始状态放入队列
170             hashState.add(convertToStrState(startMatrix));// 标记初始状态存在
171             path.put(convertToStrState(startMatrix), null);
172 
173             while (!queue.isEmpty())// 队列非空 ,进行BFS
174             {
175                 String curState = queue.poll();
176                 int[][] curMatrix = convertToMatrix(curState);
177 
178                 if (curState.equals(targetState))// 找到目标状态
179                 {
180                     break;
181                 }
182                 int curx = 0, cury = 0;
183 
184                 for (int i = 0; i < 3; i++)// 查找 0 的位置
185                 {
186                     for (int j = 0; j < 3; j++) {
187                         if (curMatrix[i][j] == 0) {
188                             curx = i;
189                             cury = j;
190                             break;
191                         }
192                     }
193                 }
194 
195                 String newState = "";// 记录新状态
196                 int[][] newMatrix = new int[3][3];// 记录新状态矩阵
197                 for (int i = 0; i < 4; i++)// BFS 相邻状态
198                 {
199                     int newx = curx + dx[i];
200                     int newy = cury + dy[i];
201                     if (newx <= 2 && newx >= 0 && newy <= 2 && newy >= 0)// 状态合法
202                     {
203 
204                         for (int j = 0; j < 3; j++) {
205                             System.arraycopy(curMatrix[j], 0, newMatrix[j], 0,
206                                     curMatrix[j].length);
207                         }
208 
209                         int temp = newMatrix[newx][newy];
210                         newMatrix[newx][newy] = newMatrix[curx][cury];
211                         newMatrix[curx][cury] = temp;
212 
213                         newState = convertToStrState(newMatrix);
214 
215                         if (!hashState.contains(newState))// 如果改状态还未到达过
216                         {
217                             path.put(newState, curState);
218                             queue.add(newState);// 把新状态压入队列
219                             hashState.add(newState);// 将新状态存入Hash
220                         }
221                     }
222                 }
223             }
224             printPath();// 打印路径
225         }
226     }
227 }

 

posted @ 2016-04-18 20:43  CodeNoob  阅读(1209)  评论(0编辑  收藏  举报