使用 C++ 使用 A* 算法解决 n 谜题
我正在 C++ 中实现 A* 算法
来解决 n-puzzle 问题。
我尝试在此链接中实现伪代码。
总成本(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);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
由于循环的可能性,即一系列移动将您带回到已经访问过的状态,因此检查重复状态非常重要(显然,这不是树搜索的问题)。我不太明白你在检查时所做的事情,但这可能就是问题所在。在编写 Haskell 实现时,我遇到了与您类似的问题(详细信息 这里和这里),这归结为处理探索集的问题。做对了,一切都会正常。 (获得 4x4 难题的解决方案仍然有点碰运气,特别是如果您从状态空间中距离目标很远的状态开始,但这主要归因于 A* 的缺陷和天真的方法我们正在处理可能的行动。)
Because of the possibility of loops, i.e. a sequence of moves that takes you back to a state you've already visited, it's important to check for duplicate states (not a problem with tree search, obviously). I can't quite follow what you're doing with your checking for this, but that's likely to be where the problem lies. I had a similar sort of problem to you when writing a Haskell implementation (details here and here), and it came down to a problem of handling the explored set. Get that right, and everything works. (Getting solutions for the 4x4 puzzle remains a bit of a hit-and-miss affair, especially if you start from a state a long way from the goal in state space, but that's mostly down to the deficiencies of A* and the naïve way we're dealing with possible moves.)
您是否删除从打开列表中选择的状态?这是一个非常简单且写得好的 C# 代码,也许可以帮助您: http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a
而且 A* 会自动避免循环,因为它会考虑您的移动
do you delete the state that you pick from your open list ? this is a C# code that is very easy and well written maybe it can help you : http://geekbrothers.org/index.php/categories/computer/12-solve-8-puzzle-with-a
and also A* automatically avoid loops because it taken the moves you take to account
我还实现了一个 n 谜题(深度优先和 a*),并且它进入了无限循环。发生这种情况是因为以下循环:上、左、下、右、上、左......
我真的不知道是否有办法防止这种事情(我能做的最大的事情就是通过记住它所做的最后一步来防止像左-右-左这样的循环......)。
不知道这是否是导致循环的原因,最好的方法是在每次迭代中打印电路板以查看真正发生的情况;)
I also made an implementation of a n-puzzle (depth first and a*) and it entered in infinite loop. This happened because of the following loop: up, left, down, right, up, left...
I really don't know if there is a way to prevent such thing (the maximum I could do was prevent loops like left-right-left... by remembering the last move it made).
Don't know if this is what causes your loop, the best way would be to in every iteration print the board to see what is really happening ;)