让老鼠走出迷宫

时间:2010-08-12 19:42:30

标签: c++ c algorithm data-structures

将大鼠放置在迷宫中某个未知位置的迷宫中。

我们所能做的就是向上,向下,向右或向左指示。我们有两种方法:

  • tryMove(< direction>)如果有墙则返回false,如果我们可以移动则返回true。
  • bool hasLadder():如果有要转义的梯子,则返回true。

我们必须编写一个函数探索,如果我们找到出路则返回true,如果没有办法则返回false。

这是一个简单的图形问题,可以使用bfs或dfs算法解决,如果我们可以找到这些地方的标记。如果我们不能标记这些地方,我们可以循环访问相同的地方。如果没有标记,有人可以帮助我让老鼠走出迷宫吗?有可能吗?

8 个答案:

答案 0 :(得分:11)

广度优先和深度优先搜索都需要内存,而天真算法可以无限循环。老鼠可能只有O(1)记忆。

解决这个问题而不记住你去过的地方的一种方法是随机选择一个方向。解决时间将非常长,但最终应达到每个可达到的方格。这与2D random步行有关。

  

令人惊讶的是,已经证明,在二维点阵上,随机步行具有到达任何点(包括起点)的统一概率,因为步数接近无穷大。

答案 1 :(得分:2)

该算法基本上是USTCON(无向st-connectivity):给定无向图 G ,确定是否存在来自节点 s 的路径(鼠标的起始位置)到节点 t (退出)。此问题出现在complexity class L中,这意味着它需要logarithmic amount of memory。所以,除非你有迷宫大小的上限,或者愿意接近,否则不可能有恒定的空间。

答案 2 :(得分:1)

没有记忆,唯一的解决方案是随机的,这很糟糕。如果您知道迷宫只是单独连接,您可以使用墙跟踪方法,但如果迷宫包含循环,则可以进入无限循环。

答案 3 :(得分:0)

您应该运行BFS算法。我看到的唯一问题是如何定义图形。它可以用von Neumann neighborhood定义。节点定义为X,Y对。伪代码应如下所示:

BFS
while (!Q.empty()){
    v = Q.top()
    neighbours = get_adj_list(v)
    foreach (w in neighbours){
        if (isWall(w) || isOutsideMaze(w)) skip
        if (isTerminal(w)) printPathAndExit
        if (dist[v] + 1 < dist[w])
            dist[w] = dist[v] + 1
            Q.push(w)
    }
}

GEN_NEIGHBOURS
dx = {-1,1}
dy = {-1,1}

get_adj_list(v)
    adj_list = []
    for (i in dx)
        for (j in dy)
            adj_list << node(v.x-i,v.y-j)
    return adj_list

编辑:现在我读的内存限制是O(1)。所以我猜你应该按照旧方法总是向右转,你最终会走出迷宫或回到起跑位置。

EDIT2 :来自Corn Maze提示:

  

与任何迷宫一样,如果始终采用右手或左手转弯,你最终会找到出路。在没有抬起迷宫的情况下,用手指伸长迷宫的墙壁会使你保持在正确的轨道上。

答案 4 :(得分:0)

这是一个经常用作家庭作业的经典问题。

试试这个:

  1. 你能告诉你现在是吗?
  2. 一旦你有了这个,你需要做些什么才能找出你是否在一条出路之内?
  3. 如果你在出路的两个步骤之内怎么样?
  4. ...

    作为Mark notes,我试图引导您的最简单的算法版本可以锁定在循环中。你怎么解决这个问题?

答案 5 :(得分:0)

如果我没记错的话,我很久以前就有这样的递归作业,但不仅限于O(1)记忆。我们无法构建我们去过的地方的“地图”并且必须使用递归...我想这将使用O(n)内存,其中n是从一开始到梯子的最短距离。

while( 1 )
    {
    if( search( MOVE_LEFT, i ) ||
        search( MOVE_UP, i ) ||
        search( MOVE_RIGHT, i ) ||
        search( MOVE_DOWN, i ) )
         {
         return TRUE;
         }
    i++;
    }

/* recursive function */
bool search( move_type move, long int length )
{

doMove( move ); /* actually move the rat to requested place */

if( hasLadder() )
    return TRUE;

if( 0 == length )
    return FALSE;

switch( move ) /* check each and return rat to previous place */
    {
    case MOVE_LEFT:  
        if( tryMove( MOVE_LEFT ) && search( MOVE_LEFT, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_UP ) && search( MOVE_UP, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_DOWN ) && search( MOVE_RIGHT, length - 1 ) ) return TRUE;      
        doMove( MOVE_RIGHT ); break;
    case MOVE_UP:
        if( tryMove( MOVE_LEFT ) && search( MOVE_LEFT, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_UP ) && search( MOVE_UP, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_RIGHT ) && search( MOVE_RIGHT, length - 1 ) ) return TRUE; 
        doMove( MOVE_DOWN ); break;
    case MOVE_RIGHT:
        if( tryMove( MOVE_UP ) && search( MOVE_UP, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_RIGHT ) && search( MOVE_RIGHT, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_DOWN ) && search( MOVE_RIGHT, length - 1 ) ) return TRUE;      
        doMove( MOVE_LEFT ); break;
    case MOVE_DOWN:
        if( tryMove( MOVE_LEFT ) && search( MOVE_LEFT, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_RIGHT ) && search( MOVE_RIGHT, length - 1 ) ) return TRUE;
        if( tryMove( MOVE_DOWN ) && search( MOVE_RIGHT, length - 1 ) ) return TRUE;      
        doMove( MOVE_UP ); break;
    }

return FALSE;

}   /* search() */

答案 6 :(得分:0)

有趣的是@mousey会问一只老鼠...... anwyay。

我已经看到这个问题已经发生了很多次。

第一个(也是天真的)解决方案是沿着左(或右)墙,但是可以制作特定的迷宫,而老鼠最终会以圆形运行。

事实上,对于我尝试过的每一个确定性的动作顺序(如2L,1R,2L,1R,......)(我在高中时都有时间),我们可以想出一个可以制造老鼠的迷宫在圈子里跑。当然,周期越复杂,迷宫越复杂。

因此,如果你有O(1)记忆,那么走出迷宫的唯一解决方案似乎是随机游走,正如Mark Byers所提出的那样。不幸的是,你不能证明用这种算法摆脱迷宫是不可能的。

另一方面,如果你有O(N)内存,它归结为创建一个地图(不知何故)。当时我最终提出的策略是在我通过的每个案例中留下pheromon(增加一个计数器),并且在选择移动时,选择最少访问的案例。然而,总是可以离开,所以我没有必要考虑终止条件,以防没有退出。

你也可以使用洪水填充算法......当然,在我了解BFS这个术语之前。这样做的好处是你有一个终止条件(当没有任何案例需要探索时)。

答案 7 :(得分:-1)

确定是否有出路对我来说听起来很像停顿问题。它可以解决所有琐碎和许多非平凡的情况,但对于许多地图,除非你可以标记你曾经在哪里,你无法证明地图不是无限的。

http://en.wikipedia.org/wiki/Halting_problem