使用难以限制的星星查找最短路径

时间:2015-12-21 20:09:53

标签: algorithm path-finding a-star

我需要解决以下问题: 我有一个网格,你可以在8个方向上移动,N,S,E,W,NE,NW,SE,SW。

正交移动成本总是1.如果前一次移动是正交的,或者前一次移动是对角线并且成本为2,则对角移动成本为1,否则成本为2。

以下几个例子可以更好地解释:

  1. 移动NE,NE将花费1 + 2 = 3

  2. 移动NE,E,NE将花费1 + 1 + 1 = 3

  3. 移动NE,NE,NE将花费1 + 2 + 1 = 4
  4. 我认为这足以得到它的要点。

    我不知道如何实现能够实现这一目标的A *算法。我的遗传功能:

    private double heuresticDistance(Node p1, Node p2){
            double dx = Math.abs(p1.x - p2.x);
            double dy = Math.abs(p1.y - p2.y);
            // D = 1d, D2 = 1.5d;
            return D * (dx + dy) + (D2 - 2 * D) * Math.min(dx, dy);
        }
    

    显然在这种情况下并不好,并且在某些情况下它不会走最短的路径(成本方面),这意味着它可能采用不同的方式来降低成本。

    如果不止一个,它总能找到最便宜的或最便宜的一个非常重要。

    你可以给我一些提示吗?我的A *实现非常简单,我想我是根据wikipedia伪代码编写的。

    编辑:

    public class Node{
        public int x,y;
    }
    

2 个答案:

答案 0 :(得分:1)

您的启发式功能不是admissible

查看从(0, 0)(1, 1)的路径。您的启发式方法告诉您它等于1 * (1 + 1) + (1.5 - 2) * 1 = 1.5。但路径是1。所以你高估了你的目标,从而使你的启发式不允许,这导致A *找到错误的路径。

仔细看看A *,你会发现它需要可接受性(我也不记得一致性对你的情况是否重要)。

答案 1 :(得分:0)

参考维基百科文章A* search algorithm。你的启发式不是“单调的”,因为给定路径的成本取决于过去的选择。这是我的尝试。

任何路径都可以分为一系列orthagonal运动和一系列对角线运动。在启发式中,让我们移动对角线直到我们与目标成对角线。这确保了最大数量的额外成本。 NE-NE-E-E

另一方面,当我们均匀地混合orthagonal和对角线运动时,最好的情况发生:E-NE-E-NE。因此,对于每个orthagonal运动,我们可以将一个对角线运动视为orthagonal。

private double heuresticDistance(Node p1, Node p2, bool lastWasDiagonal) {
    int dx = Math.abs(p1.x - p2.x);
    int dy = Math.abs(p1.x - p2.x);
    int diagonals = Math.min(dx, dy);
    int orthagonals = Math.max(dx, dy) - diagonals;
    // example: dx=3, dy=5. Move diagonally 3 times and orthagonally 2 times.

    int temp = diagonals + orthagonals;
    diagonals = Math.max(diagonals - orthagonals, 0);
    orthagonals = temp - diagonals;

    int lastDiagonalBonus = 0;
    if( lastWasDiagonal && orthagonals < 1 )
        lastDiagonalBonus = 1;  // the special case that last move was diagonal and we have no orthagonal moves available to compensate

    if( diagonals % 2 == 1 ) {
        diagonals--; orthagonals++;
    }
    return diagonals * 3 / 2 + orthagonals * 1 + lastDiagonalBonus;
}