您没有很多解决方案:基本上,探索没有循环的迷宫就像在覆盖树上进行深度优先搜索,每个交叉点都是一个节点。
您可以随时构建树,并使用该信息遍历它,但这将是乏味且效率不高的。
深度优先搜索的一种常见方法是将所有要检查的节点压入堆栈,拉出一个,然后再次压入,直到达到目标。但是你会得到很多节点堆叠起来,一旦你找到了目标节点,你就无法使用堆栈来知道你遵循了哪条路径,这意味着你需要将这些信息存储在其他地方。
最好保留堆栈解决方案并标记堆栈中的节点以指示分支,以及已探索分支的哪个方向(即哪个子树) (或留下哪些路径)。如果您始终以相同的顺序进行探索,则该标签可以只是一个数字:
或者更好的是枚举。
当发现死胡同时,只需展开堆栈直到找到其中一个节点,然后尝试新的方向。如果所有方向都已尝试,换句话说,如果没有方向,请再次放松。
enum Branch {
LEFT,
FORWARD,
RIGHT,
BACKTRACK
};
struct BacktrackException{
};
template <typename MazeMove>
struct StackNode {
MazeMove move;
Branch branch;
StackNode(MazeMove m): move(m), branch(LEFT) {}
MazeMove nextBranch(){
switch(branch){
case LEFT:
if (move.can_left()){
branch = FORWARD;
return move.left();
}
case FORWARD:
if (move.can_forward()){
branch = RIGHT;
return move.forward();
}
case RIGHT:
if (move.can_right()){
branch = BACKTRACK;
return move.right();
}
default:
throw BacktrackException();
}
}
};
上面的代码为与堆栈一起使用的可能的“MazeMove”类提供了一个包装器,它跟踪尝试的方向。nextBranch 方法返回下一个可能的移动,或抛出异常。
好处是你的筹码不会被未经尝试的动作破坏。StackNode
每次到达新位置时,您都按下 a ,并在其选项全部测试完后将其平仓。当您到达迷宫出口时,您的堆栈仅包含所需的移动。