A*算法求解8数码问题
来源:互联网 发布:json 汉字解析不出来 编辑:程序博客网 时间:2024/05/23 22:29
困扰我多日的八数码问题终于解决了,一度对八数码问题不知道该如何下手,网上很多都是用A*算法解的,但是版本可以说各有千秋,自己一时间看看各个版本的代码,也弄的头昏脑涨的,这两天一直研究A*算法,然后想通过一个实例来好好学习下A*问题,这样如果能够很好的解决典型的8数码问题,对自己也有个很好的提升。在网上看到的版本大部分都是c++的,然后我想自己就通过java来实现,毕竟用java来实现算法要容易的多,同时也易于理解。
我想从以下几个方面来阐述解决8数码问题的方法
1 了解A*算法
2 A*算法的伪代码
3 如何在8数码问题中应用A*算法(即建立合适的启发式)
4 8数码问题比较特殊,需要判断是否有可行解
5 实现A*算法在8数码问题中的应用
1 了解A*算法
在网上看了很多文章,发现一篇感觉很好的阐述了A*算法的。连接如下:A*算法
1,从起始状态A开始,并且把它作为待处理点存入一个“开启列表”。开启列表就像一张购物清单。尽管现在列表里只有一个元素,但以后就会多起来。你的路径可能会通过它包含的其他状态,也可能不会。基本上,这是一个待检查方格的列表。
2,寻找起点周围通过上下左右移动所有可到达的状态。也把他们加入开启列表。为所有这些状态保存状态A作为“父方格”。当我们想描述路径的时候,父方格的资料是十分重要的。后面会解释它的具体用途。
3,从开启列表中删除状态A,把它加入到一个“关闭列表”。
4 取出开启列表中fvalue最低的状态,判断该状态性质
(1) 如果在开启列表中出现,那么判断该状态的gvalue通过当前节点(从open中取出,扩展出该节点的节点)作为父节点带来的gvalue 是否小于原先的父节点,若小于则需要更改它的父节点以及gvalue.
(2) 如果在关闭列表中出现,那么判断该状态的gvalue通过当前节点(从open中取出,扩展出该节点的节点)作为父节点带来的gvalue是否小于原先的父节,若小于则需要从关闭列表中删除该节点,并且将其加入开启列表,并更改其父节点为当前节点。
(3) 既不在开启列表,也不在关闭列表,这样就很简单,直接加入开启列表中就行(保持开启列表升序排列)
(4) 如果取出的节点为目标节点,则成功退出
2 A*算法的伪代码
创建两个表,OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
算起点的估价值;
将起点放入OPEN表;
while(OPEN!=NULL)
{
从OPEN表中取估价值f最小的节点n;
if(n节点==目标节点){
break;
}
for(当前节点n的每个子节点X)
{
算X的估价值;
if(X in OPEN)
{
if( X的估价值小于OPEN表的X估价值 ){
把n设置为X的父亲;
更新OPEN表中的估价值; //取最小路径的估价值
}
}
if(X inCLOSE) {
if( X的估价值小于CLOSE表的X估价值 ){
把n设置为X的父亲;
将该节点从close表中除去
把X节点放入OPEN //取最小路径的估价值
}
}
if(X not inboth){
把n设置为X的父亲;
求X的估价值;
并将X插入OPEN表中; //升序排列open
}
}//end for
将n节点插入CLOSE表中;
按照估价值将OPEN表中的节点排序; //实际上是比较OPEN表内节点f的大小,从最小路径的节点向下进行。
}//end while(OPEN!=NULL)
保存路径,即从终点开始,每个节点沿着父节点移动直至起点,这就是你的路径;
A*算法有个计算公式 f(x) = g(x)+h(x)
其中g(x)为从起始状态到当前状态所消耗的步数,h(x)为一个启发值,估算从当前状态到目标状态所需的步数,一般h(x)小于等于实际需要步数为好,这样不会将最优解忽略,因为h(x)和解空间有一些关系,如果h(x)设置的比实际需要的步数多,那么解空间就有可能将最优解忽略。举个例子吧,宽度优先搜索就是h(x)=0带来的效果,深度优先搜索就是g(x)=0带来的效果,不过h(x)距离h*(x)[实际需要的步数]的程度不能过大,否则h(x)就没有过强的区分能力,算法效率并不会很高。对一个好的h(x)的评价是:h(x)在h*(n)[实际需要的步数]的下界之下,并且尽量接近h*(n)[实际需要的步数].
那么8数码问题g(x) 为经过上下左右移动空格附近的数字来得到新状态所需步数,h(x)为当前状态与目标状态的距离,就是所有不在目标位置的数字总和,必然小于h*(x)
4 8数码问题比较特殊,需要判断是否有可行解
网上的一般解法,就是通过逆序数的奇排列偶排列判断,可以在这看到逆序数介绍
当目标状态的奇偶性质和初始状态的奇偶性质相同时,才能够进行转换,具体原理我不清楚,还需要查查。
5 实现A*算法在8数码问题中的应用
import java.util.ArrayList;import java.util.Comparator;import java.util.Iterator;import java.util.List;import java.util.PriorityQueue;public class astar {public static void main(String args[]){int[][] startStatus={{2,3,1},{5,0,8},{4,6,7}}; //起始状态int[][] endStatus = {{1,2,3},{4,5,6},{7,8,0}}; //结束状态//int[][] endStatus = {{2,3,1},{5,8,7},{4,6,0}};AstarDoer test = new AstarDoer(startStatus,endStatus);test.run();}}class AstarDoer{int[][] startStatus;int[][] endStatus;NodeComparator cmp = new NodeComparator(); PriorityQueue<Node> open = new PriorityQueue<Node> (1000000,cmp); PriorityQueue<Node> close =new PriorityQueue<Node> (1000000,cmp); public AstarDoer(int[][] startStatus,int[][] endStatus ){this.startStatus = new int[3][3];this.endStatus = new int[3][3];for(int i=0;i<3;i++){for(int j=0;j<3;j++){this.startStatus[i][j] = startStatus[i][j];this.endStatus[i][j] = endStatus[i][j];}}}private int getReverse(int[][] status) //获得逆序数奇偶性{int reverse=0;for(int i=0;i<9;i++){for(int j=i+1;j<9;j++){int k = i/3;int m = i%3;if(status[k][m]>status[j/3][j%3]){reverse+=1;}}}return reverse;}private boolean check(int[][] startStatus,int[][] endStatus){//判断是否有可行解int getS =0;int getE =0;getS = getReverse(startStatus);getE = getReverse(endStatus);if((getS%2) == (getE%2) ){return true;}return false;}private void initStart(){//将开始节点加入open列表Node startNode = new Node(startStatus);startNode.gvalue = 0;startNode.parent = null;startNode.hvalue = startNode.getH(endStatus);startNode.fvalue = startNode.gvalue+startNode.hvalue;open.add(startNode);}private boolean isInList(Node lNode,Node newNodeParent){//判断该节点是否已经在之前出现过,之前出现的g值 肯定小于现在的g值,因为都是通过//同一节点经过上下左右变换得到while(newNodeParent != null){if(lNode.equal(newNodeParent.status)){return true;}newNodeParent = newNodeParent.parent;}return false;}private void initChild(Node newNode,List<Node> newNodeChild ){//生成该节点周围的子节点int whiteSpace = 0;whiteSpace = newNode.getWhitespace();/*得到空格位置判断左移产生节点*/if((whiteSpace%3) !=2){Node lNode = new Node(newNode.status);lNode.status[whiteSpace/3][whiteSpace%3] = lNode.status[whiteSpace/3][(whiteSpace%3)+1];lNode.status[whiteSpace/3][(whiteSpace%3)+1] = 0;if(isInList(lNode,newNode.parent) == false){lNode.parent = newNode;lNode.gvalue = newNode.gvalue+1;lNode.hvalue = lNode.getH(endStatus);lNode.fvalue = lNode.gvalue+lNode.hvalue;newNodeChild.add(lNode);}}/*得到空格位置判断右移产生节点*/if((whiteSpace%3) !=0){Node lNode = new Node(newNode.status);lNode.status[whiteSpace/3][whiteSpace%3] = lNode.status[whiteSpace/3][(whiteSpace%3)-1];lNode.status[whiteSpace/3][(whiteSpace%3)-1] = 0;if(isInList(lNode,newNode.parent) == false){lNode.parent = newNode;lNode.gvalue = newNode.gvalue+1;lNode.hvalue = lNode.getH(endStatus);lNode.fvalue = lNode.gvalue+lNode.hvalue;newNodeChild.add(lNode);}}/*得到空格位置判断上移产生节点*/if((whiteSpace/3) !=2){Node lNode = new Node(newNode.status);lNode.status[whiteSpace/3][whiteSpace%3] = lNode.status[whiteSpace/3+1][whiteSpace%3];lNode.status[whiteSpace/3+1][whiteSpace%3] = 0;if(isInList(lNode,newNode.parent) == false){lNode.parent = newNode;lNode.gvalue = newNode.gvalue+1;lNode.hvalue = lNode.getH(endStatus);lNode.fvalue = lNode.gvalue+lNode.hvalue;newNodeChild.add(lNode);}}/*得到空格位置判断下移产生节点*/if((whiteSpace/3) !=0){Node lNode = new Node(newNode.status);lNode.status[whiteSpace/3][whiteSpace%3] = lNode.status[whiteSpace/3-1][whiteSpace%3];lNode.status[whiteSpace/3-1][whiteSpace%3] = 0;if(isInList(lNode,newNode.parent) == false){lNode.parent = newNode;lNode.gvalue = newNode.gvalue+1;lNode.hvalue = lNode.getH(endStatus);lNode.fvalue = lNode.gvalue+lNode.hvalue;newNodeChild.add(lNode);}}}private boolean isOPenOrCloseIn(Node newNode,PriorityQueue<Node> openList){Iterator<Node> iter = openList.iterator();while(iter.hasNext()){Node iterNode = iter.next();if(iterNode.equal(newNode.status)){return true;}}return false;}public void run(){if(check(startStatus,endStatus)== false ){System.out.println("can not change to that");return;}initStart();while(open.isEmpty()==false){Node newNode = open.poll();close.add(newNode);if(newNode.equal(endStatus)){int i=0;System.out.println("success finish this Task~~~~~");while(newNode != null){for(int j=0;j<9;j++){System.out.print(newNode.status[j/3][j%3]);System.out.print(" ");if(j%3 == 2){System.out.println();}}System.out.println("step "+i+"status fvalue"+newNode.fvalue);newNode = newNode.parent;i+=1;}break;}List<Node> newNodeChild = new ArrayList<Node>();initChild(newNode,newNodeChild);for(Node iter:newNodeChild){if(isOPenOrCloseIn(iter,open) == true){Iterator<Node> iterNew = open.iterator();while(iterNew.hasNext()){Node iterNode = iterNew.next();if(iterNode.equal(iter.status)){if(iter.gvalue < iterNode.gvalue){iterNode.parent = iter.parent;iterNode.gvalue = iter.gvalue;iterNode.fvalue = iter.fvalue;}}}}else if(isOPenOrCloseIn(iter,close)==true){Iterator<Node> iterNew = close.iterator();while(iterNew.hasNext()){Node iterNode = iterNew.next();if(iterNode.equal(iter.status)){if(iter.gvalue < iterNode.gvalue){iterNode.parent = iter.parent;iterNode.gvalue = iter.gvalue;iterNode.fvalue = iter.fvalue;close.remove(iterNode);open.add(iter);}}}}else{open.add(iter);}}}} class NodeComparator implements Comparator<Node> { @Override public int compare(Node x, Node y) { return x.fvalue - y.fvalue; } } }class Node{Node parent;public int[][] status = new int[3][3];int fvalue;int gvalue;int hvalue;public Node(int[][] status){for(int i=0;i<3;i++){for(int j=0;j<3;j++){this.status[i][j] = status[i][j];}}}public void setG(int gvalue){this.gvalue = gvalue;}public int getWhitespace(){int k=0;for(int i=0;i<9;i++){if(status[i/3][i%3] == 0){k=i;return k;}}return k;}public boolean equal(int[][] endStatus){for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(status[i][j]!= endStatus[i][j]){return false;}}}return true;}public int getH(int[][] endStatus){int k=0;for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(status[i][j] != endStatus[i][j]){k+=1;}}}return k;}}
以上就是我对8数码问题的分析和解决过程,如果有问题,希望大家共同交流,终于解决了一个大难题,后面开始新的学习,加油~
- A*算法求解8数码问题
- A*算法求解15数码问题
- 根据启发函数(A*算法)求解八数码问题
- 8数码问题的A星算法
- A*算法与8数码问题
- 用IDA*算法求解八数码问题
- 八数码问题A*算法
- 八数码问题-A*算法
- 八数码问题--A*算法
- 8 位数码难题的问题求解
- 8数码问题-搜索-双向BFS/A*算法
- A*算法 cocos2dx 8数码
- 趣味编程:用BGL求解八数码问题(A*)
- 八数码问题的 A* 算法解答
- 八数码问题及A*算法
- 通过八数码问题学习A*算法
- A*算法解决八数码问题
- A*算法解决八数码问题
- 当你输入一个网址的时候,实际会发生什么?
- 某高人整理的Java就业面试题大全【3】
- 2.11-在顺序表va中插入x使仍然有序
- 杭电2001 求两点间的距离
- DP问题
- A*算法求解8数码问题
- Erlang tip累积
- 如何利用WGET下載檔案,並儲存到指定的目錄
- SEO探索四月百度算法调整 H1与title标签优化成看点
- 关于网络接口的ioctl使用
- 各种开源协议介绍 BSD、Apache Licence、GPL V2 、GPL V3 、LGPL、MIT
- asio openssl 使用
- 2.13 -实现Locate(L,x)返回x在链表中的位置
- 拦截win32 API