数据结构和算法 第二小题 九宫重排(2)

 实验任务、要求、工具上一篇里有,此处略去。

总结:本来以为是贪婪算法的思想,局部优化推导到全局优化,后来心态爆炸,怎么写也写不出来。然后发现是理解有问题。

        A*算法,yyds。本人略得皮毛,没有按照原本思想进行写,只有openlist,没有closedlist和node类,以便得到最优路径,大概算是删减版的A*算法,

体现了启发式搜索。

       写的时候发现求哈希值(全排列映射的值),用到康托展开,有Hashmap自然不用去求,但是这是建立在String的基础上,如果是数组就要求了。还有可以预先判断能不能匹配,是除点以外数字的逆序数,点移动时不会改变逆序数的奇偶性。

       感觉八数码比普通寻路算法难写,迷宫的话要更难些。

讲解:参考链接:https://blog.csdn.net/Lionel_D/article/details/43834581?ops_request_misc=&request_id=&biz_id=102&utm_term=A*%E4%B9%9D%E5%AE%AB%E9%87%8D%E6%8E%92&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-7-43834581.pc_search_result_no_baidu_js

估价函数的选取直接决定A*算法的效率,一般对于八数码问题有三种估价函数的选法:

  • 以不在位的数码的个数为估价函数
  • 以不在位的数码归位所需的最短距离和即曼哈顿距离为估价函数
  • 将逆序对数作为估价函数     

 第一种太乐观了,效率很低。第三种肉眼可见的费时间,9!。选择了第二种。由于估价还是乐观的,存在概率找到的不是最优路径。

看代码吧。。

import java.util.*;
//12345678.
//123.46758
//13524678.
//46758123.
public class Rearrange2 {
    public static int dict[][]={{0,-1},{0,1},{1,0},{-1,0}};//方向数组(左右上下遍历)
    public static String src_st;
    public static String des_st;
    public static Map<String,Integer> visited=new HashMap<>();
    public static Map<String,Integer> depth=new HashMap<>();
    public static Map<String,Integer> fmap;
    public static  List<String>list;
   public static void getF(String new_st) {//得到曼哈顿距离(所有字符)+移动距离
       int h = 0;
       for (int i = 0; i < 9; i++) {
           for (int j = 0; j < 9; j++) {
               if (new_st.charAt(i) == des_st.charAt(j)) {
                   h += Math.abs(i / 3 - j / 3) + Math.abs(i % 3 - j % 3);
               }
           }
       }
       if (depth.containsKey(new_st)) {
           fmap.put(new_st, h + depth.get(new_st));
       } else   fmap.put(new_st, h );
   }
    public static boolean judge() {//判断能不能找到
       int st=0;
       int et=0;
        for(int i = 0; i < 9 ; ++i)
        {
            if (src_st.charAt(i)=='.') continue;
            for(int j =i+1 ; j < 9 ; ++j)
            {
                if (src_st.charAt(j)=='.') continue;
                if (src_st.charAt(i)>src_st.charAt(j))
                    st++;
            }
        }
        for(int i = 0; i < 9 ; ++i)
        {
            if (des_st.charAt(i)=='.') continue;
            for(int j =i+1 ; j < 9 ; ++j)
            {
                if (des_st.charAt(j)=='.') continue;
                if (des_st.charAt(i)>des_st.charAt(j))
                    et++;
            }
        }
       return  st%2==et%2;
    }
  public static int Astar() {
       if (src_st.equals(des_st))  return 0;
      fmap = new HashMap<>();
      list = new ArrayList<>();
      list.add(src_st);
      while (true) {
          String first = list.get(getmin());
          if (first.equals(des_st)) {
              return depth.get(first);
          }
          list.remove(list.get(getmin()));
          int curX = 3;
          int curY = 3;
          for (int i = 0; i < first.length(); i++) {//定位空格位置(句点)
              if (first.charAt(i) == '.') {
                  curX = i / 3;
                  curY = i % 3;
              }
          }
          int newX, newY;
          for (int i = 0; i < 4; i++) {
              newX = dict[i][0] + curX;
              newY = dict[i][1] + curY;
              if (newX >= 0 && newX <= 2 && newY >= 0 && newY <= 2) {//判断边界条件
                  String new_st = first;
                  char curtemp = new_st.charAt(curX * 3 + curY);
                  char newtemp = new_st.charAt(newX * 3 + newY);
                  new_st = new_st.replace(curtemp, '-');//字符串交换字符
                  new_st = new_st.replace(newtemp, curtemp);
                  new_st = new_st.replace('-', newtemp);
                      depth.put(new_st,depth.get(first)+1);
                  if (!visited.containsKey(new_st)) {//这个图未访问过
                      visited.put(new_st,depth.get(new_st));
                      getF(new_st);
                      list.add(new_st);
                  }else {
                      if (depth.get(new_st)<visited.get(new_st)){//如果这个图访问过,,但是现在访问代价更小,,则更新对该图的访问代价
                          visited.put(new_st,depth.get(new_st));
                          getF(new_st);
                          list.add(new_st);
                      }
                  }

              }
          }
              String s=list.get(getmin());
              System.out.println(s);
          }
  }
   public  static int getmin(){//得到f值最小的字符串索引
       int min = 0;
       for (int j = 1; j < list.size(); j++) {
           if (fmap.get(list.get(j)) < fmap.get(list.get(min))) {
               min=j;
           }
       }
       return min;
   }
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入九宫起点字符串:");
         src_st=scanner.next();//九宫起点状态
        System.out.println("请输入九宫终点字符串:");
         des_st=scanner.next();//九宫终点状态
        visited.put(src_st,0);
        depth.put(src_st,0);
        boolean  ismatched =judge();
        if (!ismatched){
            System.out.println("人生不相见,动如参与商");
        }else {
           int  num=Astar();
            System.out.println("九宫重排搜索次数:"+"\t"+num);
        }
    }
}

 

  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值