【问题标题】:n-puzzle solving with A* algorithm using C++使用 C++ 使用 A* 算法求解 n 谜题
【发布时间】:2011-12-09 18:41:27
【问题描述】:

我正在用 C++ 实现 A* algorithm 来解决 n-puzzle 问题
我尝试在this 链接中实现伪代码。
总成本(F=H+G)的计算是“成本取决于错位瓷砖的数量(启发式)+初始状态的步骤(G)”。下面给出了AStar 函数的算法。

问题是,我遇到了无限循环的情况。我该如何解决这个问题?

PS:如果需要,我可以提供AStar 中使用的其他功能的实现。

任何帮助将不胜感激。

void AStar(const int size, int** puzzle)
{
int moveCount = 0;                                                                  // initialize G(n)
int**goalState = GoalState(size);                                                   // initialize  and assign goal state
int openListIndex = 0;                                                              // initialize open list index
vector<node> openList;                                                              // initialize open list
vector<node> closedList;                                                            // initialize closed list

node startNode;                                                                     // initialize start node
startNode.puzzleArray = puzzle;                                                     // assign start node's state
startNode.cost = moveCount + Heuristics(goalState,puzzle,size);                     // assign start node's cost

node goalNode;                                                                      // initialize goal node
goalNode.puzzleArray = goalState;                                                   // assign goal node's state

openList.push_back(startNode);                                                      // push start node to the open list

while (!openList.empty())                                                           // loop while open list is not empty
{
    node currentNode = CalculateLowestCost(&openList, &closedList);                 // initialize current node which has the lowest cost, pop it from open list, push it to the closed list
    int** currentState = currentNode.puzzleArray;                                   // initialize and assign current state array
    /*********************************************************************************************/
    if (GoalCheck(goalState, currentState, size)) break;                            // GOAL CHECK//
    /*********************************************************************************************/
    vector<char> successorDirectionList = CalculateSuccessor(size, currentState);   // initialize a char vector for the directions of the successors

    int**successor;                                                                 // initialize successor state
    node successorNode;                                                             // initialize successor node
    moveCount++;                                                                    // advance G(n)

    for (;!successorDirectionList.empty();)                                         // loop over the successor list
    {
        char direction = successorDirectionList.back();                             // take a direction from the list
        successorDirectionList.pop_back();                                          // remove that direction from the list
        successor = MoveBlank(currentState, size, direction);                       // assign successor state

        successorNode.puzzleArray = successor;                                      // assign successor node's state
        successorNode.cost = moveCount + Heuristics(goalState,currentState,size);   // assign successor node's cost

        //vector<node> stateCheckList = openList;                                   // copy the open list for the checking the nodes in that list

        bool flagOpen = false;
        bool flagClosed = false;
        int locationOpen = -1;
        int locationClosed = -1;

        for (int i=0; i<openList.size(); i++)
        {
            int** existing = openList[i].puzzleArray;
            int existingCost = openList[i].cost;

            if (StateCheck(successor, existing, size))
            {
                locationOpen = i;
                if (successorNode.cost > existingCost)
                {
                    flagOpen = true;
                    break;
                }
            }
        }
        if (flagOpen) continue;

        int** existingInOpen;
        if(locationOpen != -1) 
        {
            existingInOpen = openList[locationOpen].puzzleArray;
            openList.erase(openList.begin()+locationOpen);
        }

        for (int i=0; i<closedList.size(); i++)
        {
            int** existing = closedList[i].puzzleArray;
            int existingCost = closedList[i].cost;

            if (StateCheck(successor, existing, size))
            {
                locationClosed = i;
                if (successorNode.cost > existingCost)
                {
                    flagClosed = true;
                    break;
                }
            }
        }
        if (flagClosed) continue;

        int**existingInClosed;
        if(locationClosed != -1)
        {
            existingInClosed = closedList[locationClosed].puzzleArray;
            closedList.erase(closedList.begin()+locationClosed);
        }

        openList.push_back(successorNode);
    }    
}

}

【问题讨论】:

  • 更多的是一个问题而不是评论,但你为什么不在你有'for (;!successorDirectionList.empty();)'的地方使用'while (!successorDirectionList.empty())'?虽然你所做的当然是合法的语法,但它并不完全是典型的。
  • 我以为是一样的,有什么区别呢?在你说之后我尝试了“while”,但仍然进入无限循环。
  • 是一回事;这不是人们通常使用的。
  • 一些额外的信息也可能有用:你怎么知道有一个无限循环(而不是一个正在进行但需要很长时间的循环)?您执行了哪些测试来验证是否存在无限循环,它是哪个循环?你如何设置问题开始? IIRC,如果你从一个纯粹的随机状态开始,有些配置是无法解决的。
  • 我正在使用 3x3 板(8 拼图)进行测试,使用这种“可接受的”启发式算法,最多只能走 22 步(我认为)。顺便说一句,正如我现在测试的那样,当涉及到 2x2 时,它并没有给出无限循环。

标签: c++ heuristics a-star sliding-tile-puzzle


【解决方案1】:

您是否删除了您从开放列表中选择的状态?这是一个非常简单且编写良好的 C# 代码,也许它可以帮助您:http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a 并且 A* 会自动避免循环,因为它考虑了您采取的措施

【讨论】:

    【解决方案2】:

    由于循环的可能性,即一系列移动将您带回到您已经访问过的状态,检查重复状态很重要(显然不是树搜索的问题)。我不能完全按照你的检查来做这个,但这很可能是问题所在。在编写 Haskell 实现时,我遇到了类似的问题(详细信息 herehere),归结为处理探索集的问题。做对了,一切正常。 (获得 4x4 拼图的解决方案仍然有点碰运气,特别是如果你从一个远离状态空间目标的状态开始,但这主要是由于 A* 的缺陷和幼稚的方式我们正在处理可能的动作。)

    【讨论】:

      【解决方案3】:

      我还实现了一个 n-puzzle(深度优先和 a*),它进入了无限循环。发生这种情况是因为以下循环:上、左、下、右、上、左…… 我真的不知道是否有办法防止这种事情(我能做的最大的事情就是防止像左-右-左这样的循环......通过记住它所做的最后一步)。

      不知道这是否是导致循环的原因,最好的方法是在每次迭代中打印板以查看实际发生的情况;)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-14
        • 1970-01-01
        • 2017-01-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多