具有扩展状态对象的C#A *算法

时间:2018-12-07 04:24:34

标签: c# algorithm performance a-star

我正在尝试实现A *算法,以解决以下问题:

  1. 我有一个初始状态
  2. 我可以应用“动作”以从一种状态进入另一种状态
  3. 我想以最少的动作达到最终状态
  4. 将动作应用于给定状态很简单(=快速)
  5. 整个状态是一个复杂的对象(=内存很大,克隆速度很慢)

问题出在5 /点。

的确,当从当前状态寻找可能的子状态时,我不能每次都创建一个全新的状态,因为这样做的成本太高了(在内存和速度方面)。结果,我正在处理一个状态,当将操作应用于前一个状态时,该状态会发生突变以反映结果状态。 (我可以回滚一个动作)。我正在考虑通过以下方式实现A *:

    //_state; //represent the "singleton" states that I can apply and rollback actions instead of cloning it
    while (openNodes.Any())
    {
        var currentNode = openNodes.DeQueue();
        currentNode.AdvanceFromStart(_state); //make _state such as all action on the path from the root to currentNode are played

        if (IsFinal(_state))
            return;

        AddToVisitedStates(_state);
        foreach(var transition in currentNode.GetPossibleActions())
        {
            var childNode = new Node(initialState:_state,action:transition.Action);
            //here _state is still reflecting the situation from the currentNode point of view
            childNode.ApplyAction(_state);
            //now _state reflect the situation from childNode point of view
            if (WasVisited(_state))
            {
                childNode.RollbackAction(_state);                
                continue;
            }

            if (childNode.CostToReachNode == 0 ||
                currentNode.CostToReachNode + transition.Cost < childNode.CostToReachNode)
            {
                childNode.CostToReachNode = node.CostToReachNode + transition.CostToReachNode;
                childNode.CostToReachFinal = childNode.CostToReachNode + HeuristicToReachFinalFromState(_state);
                openNodes.ReOrder(childNode);
            }
            if (!openNodes.Contains(childNode))
                openNodes.Add(childNode);

            childNode.RollbackAction(_state);
        }
        currentNode.RollbackToInitialState(_state);//make _state as initially setup
    }

我不喜欢这种解决方案。我缺少A *算法中的某些东西会有所帮助吗?我还没有完成任务,您是否看到一些即将到来的问题/需要提出的观点?

也许A *不是正确的算法,但我很乐意接受任何导致不同之处的事情。

PD:如果相关,则用于C#实现

1 个答案:

答案 0 :(得分:0)

您可以通过将其存储在每个对象中而不是状态中,而是存储从导致该状态的初始状态开始的决策顺序,使它看起来更像普通A *。当您想处理一个状态时,请查看导致当前状态的决策顺序,将您需要进入的状态备份到公共祖先,然后查看记录的决策集。此类更改的成本最多是某些恒定因素乘以决策树的深度。如果这是高度分支和平衡的,则可能不会那么深。

另一种选择是https://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search的某些版本或“有限差异搜索”,它使用到目前为止(来自先前迭代)找到的最佳答案以及A *启发式算法来避免节点不可能导致可能的答案。在修整一次(修整后)当前对差异或深度的限制并没有真正阻止您调查每个想要的节点时,您知道找到了最佳答案。