算法學習之8數碼問題

  這幾天都在寫人工智能和信息安全做業,沒怎麼學算法書,不過如今上的課也多多少少在學算法相關的,此次實驗,咱們人工智能老師就是要求咱們解決八數碼問題。java

首先咱們要知道什麼是八數碼問題:算法

  八數碼問題:在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* 算法)編程求解八數碼問題(初始狀態任選),並對實驗結果進行分析,得出合理的結論。spa

  這裏我爲了簡單點用的bfs(寬度優先搜索),首先給出矩陣後爲了方便處理(標記是否出現過)轉爲一維字符串形式,code

/**
    * 把存儲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;
   }

而後判斷由初始矩陣轉目標矩陣是否有解,如何判斷是否有解我在網上找了下,是判斷初始矩陣的狀態字符串的逆序數與目標矩陣的狀態字符串的逆序數是否同奇或者同偶,若是同是奇數或同是偶數就有解。否者無解。blog

/**
    * 判斷是否能夠由初始的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 }
相關文章
相關標籤/搜索