數碼問題求解,分別使用BFS和啓發式搜索實現。java
BFS:求解指定3*3拼圖(8-數碼問題)的最優解。node
1,isCompleted記錄求解完成狀態;數組
2,closeList記錄全部訪問過的節點;函數
3,searchedNodesNum記錄訪問過的節點數;this
4,solutionPath記錄解路徑。spa
public boolean BFSearch() throws IOException { // 將搜索過程寫入D://BFSearchDialog.txt String filePath = "BFSearchDialog.txt"; PrintWriter pw = new PrintWriter(new FileWriter(filePath)); // ************************************* JigsawNode beginnode = getBeginJNode(); openList.add(beginnode); isCompleted = false; // 判斷廣搜結束條件 while (!openList.isEmpty()) { // 判斷是否到達目標狀態 JigsawNode root = openList.firstElement(); currentJNode = root; if (getCurrentJNode().equals(getEndJNode())) { isCompleted = true; break; } // 訪問openList的第一個節點,將相鄰的 且未被訪問的(在closeList中找不到)的節點加入openList Vector<JigsawNode> neighbornodes = new Vector<JigsawNode>(); neighbornodes = findFollowJNodes(root); openList.addAll(neighbornodes); openList.removeElementAt(0); closeList.add(root); searchedNodesNum++; } if (isCompleted) { calSolutionPath(); } // ************************************* this.printResult(pw); pw.close(); System.out.println("Record into " + filePath); return isCompleted; }
啓發式搜索:code
訪問節點數大於30000個則認爲搜索失敗。排序
函數結束後:isCompleted記錄了求解完成狀態;索引
closeList記錄了全部訪問過的節點;element
searchedNodesNum記錄了訪問過的節點數;
solutionPath記錄瞭解路徑。
public boolean ASearch() throws IOException{ // 將搜索過程寫入ASearchDialog.txt String filePath = "ASearchDialog.txt"; PrintWriter pw = new PrintWriter(new FileWriter(filePath)); // 訪問節點數大於25000個則認爲搜索失敗 int maxNodesNum = 25000; // 用以存放某一節點的鄰接節點 Vector<JigsawNode> followJNodes = new Vector<JigsawNode>(); // 重置求解完成標記爲false isCompleted = false; // (1)將起始節點放入openList中 this.sortedInsertOpenList(this.beginJNode); // (2) 若是openList爲空,或者訪問節點數大於maxNodesNum個,則搜索失敗,問題無解;不然循環直到求解成功 while (this.openList.isEmpty() != true && searchedNodesNum <= maxNodesNum) { // (2-1)訪問openList的第一個節點N,置爲當前節點currentJNode // 若currentJNode爲目標節點,則搜索成功,設置完成標記isCompleted爲true,計算解路徑,退出。 this.currentJNode = this.openList.elementAt(0); if (this.currentJNode.equals(this.endJNode)){ isCompleted = true; this.calSolutionPath(); break; } // (2-2)從openList中刪除節點N,並將其放入closeList中,表示以訪問節點 this.openList.removeElementAt(0); this.closeList.addElement(this.currentJNode); searchedNodesNum++; // 記錄並顯示搜索過程 pw.println("Searching.....Number of searched nodes:" + this.closeList.size() + " Current state:" + this.currentJNode.toString()); System.out.println("Searching.....Number of searched nodes:" + this.closeList.size() + " Current state:" + this.currentJNode.toString()); // (2-3)尋找全部與currentJNode鄰接且不曾被訪問的節點,將它們按代價估值從小到大排序插入openList中 followJNodes = this.findFollowJNodes(this.currentJNode); while (!followJNodes.isEmpty()) { this.sortedInsertOpenList(followJNodes.elementAt(0)); followJNodes.removeElementAt(0); } } this.printResult(pw); // 記錄搜索結果 pw.close(); // 關閉輸出文件 System.out.println("Record into " + filePath); return isCompleted; } /* 計算並修改狀態節點jNode的代價估計值:f(n)=s(n)。 * s(n)表明後續節點不正確的數碼個數 * @param jNode - 要計算代價估計值的節點;此函數會改變該節點的estimatedValue屬性值。 */ private void estimateValue(JigsawNode jNode) { int fn = 0; // 後續節點不正確的數碼個數 int s = 0; // 全部 放錯位的數碼與其正確位置的距離 之和 int errordis = 0; // 全部 放錯位的數碼 個數 int errornum = 0; int index; // 空格的索引下標 int spaceindex = 0; // 該Node的數組 int[] nodestate = jNode.getNodesState(); int dimension = JigsawNode.getDimension(); for(index =1 ; index<dimension*dimension; index++){ if(nodestate[index]+1!=nodestate[index+1]) { s++; } } for (index =1 ; index<dimension*dimension; index++) { if(index != nodestate[spaceindex] && nodestate[index] != index) { errornum++; // 求解曼哈頓距離 // 當前座標 int cx, cy, dx,dy; cx = (index - 1) / dimension; cy = (index -1 ) % dimension; dx = (nodestate[index] - 1) / dimension; dy = (nodestate[index] -1) % dimension; errordis = errordis+Math.abs(dx-cx) + Math.abs(dy-cy); } } fn = 2*s + errordis + errornum; jNode.setEstimatedValue(fn); }