【问题标题】:Why does A* not find the optimal path?为什么 A* 没有找到最优路径?
【发布时间】:2013-06-11 12:47:19
【问题描述】:

我在一个简单的 Winforms 应用程序中实现了 A*-pathfinding。还可以在网格上定义障碍物,以便代理可以在它们周围导航。

问题是我的代理无法预见路径。这就是为什么他并不总是选择最优路径。

Here you can see my exact problem.

如何让探路者预测较短的路径?一旦代理走错路,也会出现死胡同的问题。

此方法获取相邻单元格并计算值:

public void addAdjascent(Vector pos) 
    {

        foreach(Cell cell in allCells)
        {
            bool containedInClosedList = closedList.Any(c => c.id == cell.id);

            if (!containedInClosedList)
            {


            if (cell.positionCR.X == pos.X - 1 && cell.positionCR.Y == pos.Y)
            {

                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if(!containedInBlockedList)
                {
                    cell.H = calcH(goal,cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }



            }

            if (cell.positionCR.X == pos.X + 1 && cell.positionCR.Y == pos.Y)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X  && cell.positionCR.Y == pos.Y - 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }


            }

            if (cell.positionCR.X == pos.X && cell.positionCR.Y == pos.Y + 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }                    
            }

            if (cell.positionCR.X == pos.X - 1 && cell.positionCR.Y == pos.Y - 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X - 1 && cell.positionCR.Y == pos.Y + 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X + 1 && cell.positionCR.Y == pos.Y - 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            if (cell.positionCR.X == pos.X + 1 && cell.positionCR.Y == pos.Y + 1)
            {
                bool containedInBlockedList = blockedList.Any(c => c.id == cell.id);

                if (!containedInBlockedList)
                {
                    cell.H = calcH(goal, cell);
                    cell.G = calcG(start, cell);
                    cell.F = cell.G + cell.H;
                    openList.Add(cell);
                }
            }

            }

        }
    }

这里是计算G和H值的代码:

    public int calcG(Vector start,Cell cell) 
    {
        int distance = closedList.Count;

        return distance;
    }

    public int calcH(Vector goal, Cell cell) 
    {

        int distance;

        int distanceX = (goal.X) - cell.positionCR.X;
        int distanceY = (goal.Y) - cell.positionCR.Y;

        if (distanceX < 0)
        {
            distanceX = distanceX * -1;
        }

        if (distanceY < 0)
        {
            distanceY = distanceY * -1;
        }

        distance = distanceX + distanceY;

        return distance;

    }

最后我计算出我想踩的下一个单元格:

public void step() 
    {
        addAdjascent(stepPos);
        bool foundDestination = false;
        int min = 8000;

        foreach(Cell openCell in openList)
        {
            if (openCell.F < min) 
            {
                min = openCell.F;
            }
        }

        if(openList.Count > 0)
        {
            foreach (Cell openCell in openList)
            {
                if (openCell.positionCR.X == goal.X && openCell.positionCR.Y == goal.Y)
                {
                    closedList.Add(openCell);
                    stepPos = openCell.positionCR;
                    foundDestination = true;
                }
            }
        }            

        if(!foundDestination)
        {
            closedList.Add(openList.First(item => item.F == min));
            stepPos = openList.First(item => item.F == min).positionCR;

        }

        openList.Clear();
    }

【问题讨论】:

  • 那属于你的算法问题。
  • 你能告诉我们你的代码吗?
  • +1 太酷了!不过不确定它与 WinForms 有什么关系。
  • 这个 A* 怎么样?您显然没有使用 A* 计算最佳路径,然后执行该路径。您只是在接受 A* 的第一个猜测。您只使用了 A* 算法的一个循环,并指责它在找到实际最佳路径之前没有做与循环相同的事情。
  • @RenéWolferink:非常感谢,在这里也找到了一个非常好的:dotnetperls.com/pathfinding

标签: c# winforms optimization path-finding a-star


【解决方案1】:

您的实现问题在于您尚未完全实现 A* 算法。您只实现了(在您的 step 方法中)算法中单个步骤的下一个最佳猜测。

该算法应完全执行,直到达到终点并且您的打开列表中不再有较短的路径(估计)。完成此操作后,您可以根据结果构建最短路径。然后你就可以迈出正确的一步了。

A* 从来没有打算在没有实际计算整个路径的情况下立即给出下一步应该做什么的答案。如果实施正确,它将为您提供最佳路径,只要您从给定点估计余数的启发式方法从不高估实际剩余距离。

我建议进一步阅读 A* 算法应该如何实现。一个好的开始可能是wikipedia

【讨论】:

  • 我认为为了让代码在每次迭代中搜索不同的路径,我必须以某种方式改变这个:openList.First(item => item.F == min)。我怎么能总是做出与之前迭代不同的决定?
  • 我认为最好看一些示例,了解您通常如何实现它们。看看这个问题链接的例子:stackoverflow.com/questions/2138642/…
【解决方案2】:

Dijkstra 也有类似的问题,尽管他是基于权重的。

它可能有助于 Peek() 位置,然后评估其在所有位置从 Peek().Peek() 移动的能力。与可导航路径相比,任何无法使用的位置都可能具有极高的权重。

但是这些算法可以完全使用递归来解决,然后从中选择最佳路线。

(我还注意到您在视频中沿对角线移动,这实际上是一个有效的移动,因为直接向上移动将具有相同的 2 个方格的净距离)。

【讨论】:

【解决方案3】:

A* 不是找到最佳路径的算法 - 如果最佳路径是您所追求的,那么您将不得不使用蛮力方法。 A*(基于启发式函数的质量)找到接近最优的路径。

【讨论】:

  • 值得注意的是,如果启发式是可接受的,则该算法是最优的。
  • 同意。如果启发式是可接受的,即如果它从不高估目标成本,则保证最佳路径。
【解决方案4】:

如果正确实施的 A* 正在生成非最佳路径,我认为您的启发式方法是不可接受的。一个可接受的启发式算法必须永远不要高估到目标的剩余距离。如果是这样,您在视频中显示的内容就会发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    相关资源
    最近更新 更多