二维地图的寻路算法2

来源:互联网 发布:unitedstack 知乎 编辑:程序博客网 时间:2024/03/29 14:14

    二维地图的寻路算法2。

    首先需要说明本算法得到的解不一定是最优解,但是比普通的回溯算法速度要快。

    代码如下:

  1. import java.util.Stack;
  2. /**
  3.  * 找到从地图上一个点到另一个点的路径
  4.  * 
  5.  * @author cuilichen
  6.  * 
  7.  */
  8. public class FindPath {
  9.     /**
  10.      * 用来存放操作步骤的栈
  11.      */
  12.     private Stack stack = new Stack();
  13.     /**
  14.      * 地图的宽度
  15.      */
  16.     private int wid = 8;
  17.     /**
  18.      * 找到从地图上一个点到另一个点的路径
  19.      * 
  20.      * @param map
  21.      * @param origin
  22.      * @param target
  23.      * @return
  24.      */
  25.     public String find(byte[] map, int origin, int target) {
  26.         if (origin == target) {
  27.             return "";
  28.         }
  29.         int[] step = new int[10];
  30.         step[1] = origin;
  31.         judge(map, step, target);
  32.         stack.push(step);// 根节点
  33.         if (!findPath(map, target)) {// 没有找到路径
  34.             return null;
  35.         }
  36.         optimize(stack);
  37.         StringBuffer sb = new StringBuffer();
  38.         for (int i = 1; i < stack.size(); i++) {
  39.             step = (int[]) stack.elementAt(i);
  40.             sb.append((char) step[0]);
  41.         }
  42.         return sb.toString();
  43.     }
  44.     /**
  45.      * 得到相邻4个点的评价值(距目标点的直线距离的平方),并按照从小到大的顺序排列。
  46.      * 
  47.      * @param map
  48.      * @param node
  49.      * @param target
  50.      */
  51.     private void judge(byte[] map, int[] node, int target) {
  52.         int origin = node[1];
  53.         int x0 = origin % wid;
  54.         int y0 = origin / wid;
  55.         int x1 = target % wid;
  56.         int y1 = target / wid;
  57.         int distance = 0;
  58.         distance = (x0 - 1 - x1) * (x0 - 1 - x1) + (y0 - y1) * (y0 - y1);// 左边
  59.         node[2] = 'l';
  60.         node[3] = distance;
  61.         distance = (x0 + 1 - x1) * (x0 + 1 - x1) + (y0 - y1) * (y0 - y1);// 右边
  62.         node[4] = 'r';
  63.         node[5] = distance;
  64.         distance = (x0 - x1) * (x0 - x1) + (y0 - 1 - y1) * (y0 - 1 - y1);// 上
  65.         node[6] = 'u';
  66.         node[7] = distance;
  67.         distance = (x0 - x1) * (x0 - x1) + (y0 + 1 - y1) * (y0 + 1 - y1);// 下
  68.         node[8] = 'd';
  69.         node[9] = distance;
  70.         int direct;
  71.         for (int i = 2; i < node.length; i += 2) {// 冒泡法排序,按照评价值从小到大的顺序
  72.             for (int j = i + 2; j < node.length; j += 2) {
  73.                 if (node[j + 1] < node[i + 1]) {
  74.                     direct = node[j];
  75.                     distance = node[j + 1];
  76.                     node[j] = node[i];
  77.                     node[j + 1] = node[i + 1];
  78.                     node[i] = direct;
  79.                     node[i + 1] = distance;
  80.                 }
  81.             }
  82.         }
  83.     }
  84.     /**
  85.      * 在地图上找到从原点到目标位置的路径
  86.      * 
  87.      * @param map
  88.      * @param origin
  89.      * @param target
  90.      * @return
  91.      */
  92.     private boolean findPath(byte[] map, int target) {
  93.         int[] node = (int[]) stack.peek();
  94.         for (int i = 2; i < node.length; i += 2) {
  95.             if (node[i + 1] >= 0) {
  96.                 if (canMoveTo(map, node, i, target)) {
  97.                     return true;
  98.                 } else {
  99.                     node[i + 1] = -1;
  100.                 }
  101.             }
  102.         }
  103.         stack.pop();// 如果四个方向都试过,全部不行,那么把当前步骤弹出
  104.         return false;
  105.     }
  106.     /**
  107.      * 是否可以向指定方向移动
  108.      * 
  109.      * @param map
  110.      * @param origin
  111.      * @param target
  112.      * @param direct
  113.      * @return
  114.      */
  115.     private boolean canMoveTo(byte[] map, int[] node, int index, int target) {
  116.         int next = 0;
  117.         switch (node[index]) {
  118.         case 'l':
  119.             next = node[1] - 1;
  120.             break;
  121.         case 'r':
  122.             next = node[1] + 1;
  123.             break;
  124.         case 'u':
  125.             next = node[1] - wid;
  126.             break;
  127.         case 'd':
  128.             next = node[1] + wid;
  129.             break;
  130.         }
  131.         if (map[next] == 0) {// 如果目标位置可以进入
  132.             if (next == target) {
  133.                 int[] step = new int[10];
  134.                 step[0] = node[index];// 移动方向
  135.                 step[1] = next;// 到达的新位置
  136.                 stack.push(step);
  137.                 return true;
  138.             }
  139.             if (!inStack(next)) {
  140.                 int[] step = new int[10];
  141.                 step[0] = node[index];
  142.                 step[1] = next;
  143.                 this.judge(map, step, target);
  144.                 stack.push(step);
  145.                 if (findPath(map, target)) {
  146.                     return true;
  147.                 }
  148.             }
  149.         }
  150.         return false;
  151.     }
  152.     /**
  153.      * 检查这个位置是否在栈中已经存在了。为了防止在地图中转圈
  154.      * 
  155.      * @param posi
  156.      * @return
  157.      */
  158.     private boolean inStack(int posi) {
  159.         int[] temp;
  160.         for (int i = stack.size() - 1; i >= 0; i--) {
  161.             temp = (int[]) stack.elementAt(i);
  162.             if (posi == temp[1]) {
  163.                 return true;
  164.             }
  165.         }
  166.         return false;
  167.     }
  168.     /**
  169.      * 进行简单的优化,如果原始路径是“口”字形的三边,那么优化成走一条边
  170.      * 
  171.      * @param stack
  172.      */
  173.     private void optimize(Stack stack) {
  174.         for (int i = 0; i < stack.size() - 3; i++) {
  175.             int[] step1 = (int[]) stack.elementAt(i);
  176.             int[] step2 = (int[]) stack.elementAt(i + 1);
  177.             int[] step3 = (int[]) stack.elementAt(i + 2);
  178.             if (step1[0] != step2[0] && step1[0] != step3[0]
  179.                     && step2[0] != step3[0]) {
  180.                 int[] step = new int[10];
  181.                 step[0] = step2[0];
  182.                 step[1] = step3[1];
  183.                 stack.removeElementAt(i + 2);
  184.                 stack.removeElementAt(i + 1);
  185.                 stack.removeElementAt(i);
  186.                 stack.insertElementAt(step, i);
  187.             }
  188.         }
  189.     }
  190.     /**
  191.      * 测试上述功能是否实现了
  192.      * 
  193.      * @param args
  194.      */
  195.     public static void main(String[] args) {
  196.         byte[] map = { 11111111
  197.                 11110011
  198.                 10000011
  199.                 10110011
  200.                 10001011,
  201.                 10100011
  202.                 10001011
  203.                 11111111 };
  204.         FindPath ai = new FindPath();
  205.         for (int i = 0; i < map.length; i++) {
  206.             System.out.print(map[i] + " ");
  207.             if (i % ai.wid == ai.wid - 1) {
  208.                 System.out.print("/n");
  209.             }
  210.         }
  211.         System.out.print("/n");
  212.         String s = ai.find(map, 1350);
  213.         System.out.println(s);
  214.     }
  215. }

 

The result as following:

 

1 1 1 1 1 1 1 1
1 1 1 1 0 0 1 1
1 0 0 0 0 0 1 1
1 0 1 1 0 0 1 1
1 0 0 0 1 0 1 1
1 0 1 0 0 0 1 1
1 0 0 0 1 0 1 1
1 1 1 1 1 1 1 1

 

dllllddddr

 

即,路径是:下,左,左,左,左,下,下,下,下,右。这个路径用了10步。

从地图中,我们可以看出有另一条路径:下,下,下,下,左,左,下,左。可以只用8步就完成。

所以,本算法不是一个最优解算法。

 

另外,评价值函数的影响很大,本文中简单的使用了距离的平方作为评价值,比较粗糙。

大家可以多想想,提出宝贵意见。

原创粉丝点击