您的位置:首页 > 其它

BFS和A*算法分别解决N-数码问题

2015-05-28 11:22 363 查看
数码问题求解,分别使用BFS和启发式搜索实现。

BFS:求解指定3*3拼图(8-数码问题)的最优解。

1,isCompleted记录求解完成状态;

2,closeList记录所有访问过的节点;

3,searchedNodesNum记录访问过的节点数;

4,solutionPath记录解路径。

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


启发式搜索:

访问节点数大于30000个则认为搜索失败。

函数结束后:isCompleted记录了求解完成状态;

closeList记录了所有访问过的节点;

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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: