在PHP中验证A *实现PHP

2023-09-11 04:37:37 作者:沵若安好,哎哟我操

这是我从网站这里一个code我想知道这个实现的*是否正确。我见过他,并与维基百科页面进行比较,似乎有效。为什么我想问的原因是因为在网站上说,它仍然有这个code中的错误,我试图找到它,但不能狼狈不堪。我希望如此,它需要的始发地和目的地作为输入参数,但改变它

This is a code that I got from the site here and I'd like to know whether this implementation of A* is correct. I have looked at it and compare it with the wikipedia page and it seems valid.. The reason why I ask is because in the site it says there is still a bug in this code, I tried finding it but can't find any. I want to change it though so that it takes an origin and destination as input parameter

<?php

class AStarSolver
{
    function solve(&$s)
    {
        include_once('PQueue.class.php');
        $o = new PQueue();
        $l = array();
        $c = array();
        $p = array();
        $a = $s->getStartIndex();
        $z = $s->getGoalIndex();
        $d = $s->goalDistance($a);

        $n0 = array('g'=>0, 'h'=>$d, 'i'=>$a, 'p'=>NULL, 'f'=>$d);
        $o->push($n0, -$d);
        $l[$a] = TRUE;

        while (! $o->isEmpty())
        {
            $n = $o->pop();

            if ($n['i'] == $z)
            {
                while ($n)
                {
                    $p[] = $n['i'];
                    $n = $n['p'];
                }
                break;
            }

            foreach ($s->getNeighbors($n['i']) as $j => $w)
            {
                if ((isset($l[$j]) || isset($c[$j])) && isset($m) && $m['g'] <= $n['g']+$w)
                    continue;

                $d = $s->goalDistance($j);
                $m = array('g'=>$n['g']+$w, 'h'=>$d, 'i'=>$j, 'p'=>$n, 'f'=>$n['g']+$w+$d);

                if (isset($c[$j]))
                    unset($c[$j]);

                if (! isset($l[$j]))
                {
                    $o->push($m, -$m['f']);
                    $l[$j] = TRUE;
                }
            }
            $c[$n['i']] = $n;
        }
        return $p;
    }

}

?>

在code到Pqueue可以发现这里

推荐答案

该网站显示,该漏洞可能会在 PQueue 类。

The site suggests that the bug might be in the PQueue class.

PQueue ::流行

$j+1 < $m

是测试是否堆节点在 $ I 有一个孩子(在附加$ J )或两个(在附加$ J $ J + 1 )。

is a test whether the heap node at $i has one child (at $j) or two (at $j and $j+1).

$ M 这里是计数($ H)只能通过循环的第一次迭代,因为 - $ M 的循环条件,每次评估

But $m here is count($h) only on the first iteration through the loop, since the --$m in the loop condition is evaluated every time.

此举 - $ M 旁边的 array_pop 它所属,这将是少了一个错误

Move that --$m next to the array_pop where it belongs, and that will be one less bug.

现在的 AStarSolver

的变量(相对于维基百科伪code )

$ 0 - 开集的优先级队列; $ L - 开集的地图通过索引键控; $ C - 闭集的映射通过索引键控; $ N - 当前节点( X 的); $ M - 邻居节点(是的); 附加$ J - 邻居节点指数 $o – open set as priority queue; $l – open set as map keyed by index; $c – closed set as map keyed by index; $n – current node (x); $m – neighbour node (y) ?; $j – neighbour node index.

的问题,我看到的:

$ N = $邻&GT;流行()后面没有取消设置($ L [$ N ['我'])。由于两个 $ 0 $ L 重present同一组,它们应该保持同步。

$n = $o->pop() isn't followed by unset($l[$n['i']]). Since both $o and $l represent the same set, they should be kept in sync.

根据维基百科的闭集仅用于当启发是的单调的(我认为的距离启发式是单调),在这种情况下,一旦一个节点添加到闭集,它永远不会再次访问。这code似乎实现一些其它伪code ,它不删除节点从闭集。我认为这违背了闭集的目的,并在内部循环的首要条件应该是

According to Wikipedia the closed set is only used if the heuristic is monotone (and I think a distance heuristic is monotone), and in that case, once a node is added to the closed set, it is never visited again. This code seems to implement some other pseudocode, which does remove nodes from the closed set. I think this defeats the purpose of the closed set, and the first condition in the inner loop should be

如果(使用isset($ C [$ J])||使用isset($ L [$ J])及和放大器;使用isset($ M)及和放大器; $ M ['G' ]&LT; = $ N ['G'] + $ W)

然后我们就可以删除取消设置($ C [$ J]。)

$ M ['G'] 在这种情况下应该是先按g 的-score当前的邻居通过附加$ J 。但 $ M 的任何值从previous循环遗留下来:该节点对应于附加$ J 上一个previous迭代。

$m['g'] in this condition should be the g-score of the current neighbour indexed by $j. But $m has whatever value is left over from the previous loop: the node corresponding to $j on a previous iteration.

我们需要的是一种能够找到一个节点,它的先按g 的-score由节点索引。我们可以存储在 $ L 数组中的节点:我们做的,而不是 $ L [$ J] = TRUE $ L [$ J] = $ M 和上面的条件变得

What we need is a way to find a node and its g-score by node index. We can store the node in the $l array: instead of $l[$j] = TRUE we do $l[$j] = $m and the above condition becomes

如果(使用isset($ C [$ J])||使用isset($ L [$ J])及和放大器; $ L [$ J] ['G']&LT; = $ N ['G'] + $ W)

现在的有点棘手。如果我们只是找到该节点不是在开集,我们将其添加​​有(这是 $邻&GT;推 $ L [$ J] = )。

Now the tricky bit. If the node we just found is not in the open set, we add it there (that's the $o->push and $l[$j] =).

不过,如果是在开集,我们只是找到了一个更好的路径,所以我们必须更新。在code没有做到这一点,它的棘手,因为优先级队列不增加元素的优先级提供程序。然而,我们可以完全重建优先级队列和code在内部循环的最后一个比特

However, if it is in the open set we just found a better path to it, so we must update it. The code doesn't do this and it's tricky because the priority queue doesn't provide a routine for increasing the priority of an element. However, we can rebuild the priority queue completely and the last bit of code in the inner loop becomes

如果(!使用isset($ L [$ J])){ $邻&GT;推($ M, - $ M ['F']); $ L [$ J] = $米; //添加新元素 }其他{ $ L [$ J] = $米; //替换现有的元素 $ O =新PQueue(); 的foreach($ L为$ M) $邻&GT;推($ M, - $ M ['F']); }

if (! isset($l[$j])) {    $o->push($m, -$m['f']);    $l[$j] = $m; // add a new element } else {    $l[$j] = $m; // replace existing element    $o = new PQueue();    foreach ($l as $m)       $o->push($m, -$m['f']); }

这是不是非常有效,但它是一个起点。在更改优先级队列中的元素不是有效的,无论如何,因为你首先得的查找的吧。

This is not terribly efficient, but it's a starting point. Changing an element in a priority queue isn't efficient anyway, because you first have to find it.

即使没有这些改变的算法确实找到一个路径,只是没有的最佳路径。你可以看到它在提到迷宫:

Even without these changes the algorithm does find a path, just not the best path. You can see it in the mentioned mazes:

疯狂迷宫第三内部电路:在拍摄上的路径周围略长于下路径将是因为在该障碍离开了。 某APP软件网络授权验证系统php源码 免费版

In the crazy maze in the third inner circuit: the taken upper path around is slightly longer than the lower path would have been because of the obstacles on the left.

迷宫路径中有不必要的循环上升的右上部分。

In the big maze in the upper-right part of the path there's an unnecessary loop up.

由于这是在我的脑海,我实现了我自己的版本的算法并张贴在回答你的$p$pvious问题。

Since this was on my mind, I implemented my own version of the algorithm and posted it in an answer to your previous question.