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

数码问题求解,分别使用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);
    }


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值