【问题标题】:How to find the fastest route in a maze (in C) [duplicate]如何在迷宫中找到最快的路线(C)[重复]
【发布时间】:2015-12-13 21:07:00
【问题描述】:

迷宫被定义为一个方阵。 例如:

int maze[N][N] =
  { { 1, 1, 1, 1, 1, 1, 1 },
    { 0, 1, 0, 1, 0, 0, 1 },
    { 0, 1, 0, 1, 1, 1, 1 },
    { 0, 1, 0, 0, 0, 1, 1 },
    { 0, 1, 1, 1, 0, 1, 1 },
    { 0, 0, 1, 0, 1, 1, 1 },
    { 1, 1, 1, 1, 0, 1, 1 } };

你只能走到有 1 的地方。 您可以向下,向上,向左,向右走一步。 您从左上角开始,在右下角结束。

输出应该是完成任何迷宫的最少步骤。 我们可以假设至少有一种方法可以完成迷宫。 我已经编辑了代码,我以为我涵盖了所有内容..但显然我遗漏了一些东西。 感谢您的帮助

int path_help(int maze[][N], int row, int col, int count)
{
    int copy1[N][N], copy2[N][N], copy3[N][N];
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            copy1[i][j] = maze[i][j];
            copy2[i][j] = maze[i][j];
            copy3[i][j] = maze[i][j];
        }
    }
    int a, b, c, d;
    if (col == 0 || row == 0)
    {
        if (row == N - 1)
        {
            if (maze[row][col + 1] == 1)
            {
                maze[row][col] = 0;
                return path_help(maze, row, col + 1, count + 1);
            }
            else return N*N;
        }
        if (col == N - 1)
        {
            if (maze[row + 1][col] == 1)
            {
                maze[row][col] = 0;
                return path_help(maze, row + 1, col, count + 1);
            }
            else return N*N;
        }
        if (maze[row][col + 1] == 1 && maze[row + 1][col] == 1)
        {
            maze[row][col] = 0;
            copy1[row][col] = 0;
            return min(path_help(copy1, row, col + 1, count + 1),path_help(maze, row + 1, col, count + 1));
    }
    if (maze[row][col + 1] == 0 && maze[row + 1][col] == 1)
    {
        maze[row][col] = 0;
        return path_help(maze, row + 1, col, count + 1);
    }
    if (maze[row + 1][col] == 0 && maze[row][col + 1] == 1)
    {
        maze[row][col] = 0;
        return path_help(maze, row, col + 1, count + 1);
    }
    else return N*N;
}
if (col == N - 1 || row == N - 1)
{
    if (col == N - 1 && row == N - 1) return count;
    if (row == N - 1)
    {
        if (maze[row - 1][col] == 1 && maze[row][col + 1] == 1)
        {
            maze[row][col] = 0;
            copy1[row][col] = 0;
            return min(path_help(copy1, row, col + 1, count + 1), path_help(maze, row - 1, col, count + 1));
        }

        if (maze[row - 1][col] == 0 && maze[row][col + 1] == 1)
        {
            maze[row][col] = 0;
            return path_help(maze, row, col + 1, count + 1);
        }
        if (maze[row][col + 1] == 0 && maze[row - 1][col] == 1)
        {
            maze[row][col] = 0;
            return path_help(maze, row - 1, col, count + 1);
        }
        else return N*N;
    }
    if (col == N - 1)
    {
        if (maze[row + 1][col] == 1 && maze[row][col - 1] == 1)
        {
            maze[row][col] = 0;
            copy1[row][col] = 0;
            return min(path_help(copy1, row, col - 1, count + 1), path_help(maze, row + 1, col, count + 1));
        }

        if (maze[row + 1][col] == 0 && maze[row][col - 1] == 1)
        {
            maze[row][col] = 0;
            return path_help(maze, row, col - 1, count + 1);
        }
        if (maze[row][col - 1] == 0 && maze[row + 1][col] == 1)
        {
            maze[row][col] = 0;
            return path_help(maze, row + 1, col, count + 1);
        }
        else return N*N;
    }
}
if (maze[row + 1][col] == 1)
{
    maze[row][col] = 0;
    a = path_help(maze, row + 1, col, count + 1);
}
else a = N*N;
if (maze[row - 1][col] == 1)
{
    copy1[row][col] = 0;
    b = path_help(copy1, row - 1, col, count + 1);
}
else b = N*N;
if (maze[row][col + 1] == 1)
{
    copy2[row][col] = 0;
    c = path_help(copy2, row, col + 1, count + 1);
}
else c = N*N;
if (maze[row][col - 1] == 1)
{
    copy3[row][col] = 0;
    d = path_help(copy3, row, col - 1, count + 1);
}
else d = N*N;
return min(min(a, b),min( c, d));

}

【问题讨论】:

  • 什么不起作用。你的程序的输出是什么,你期望什么输出?你有什么想法会出什么问题吗?
  • 那是邪恶的:在 switch 中嵌套的 switch 没有适当的缩进!我并不惊讶它不起作用。我有点惊讶它可以编译,但是有 Duff's Device 所以我并不完全感到惊讶。
  • 你的代码怎么知道它在哪里?它如何知道它何时达到了边缘?它如何知道它何时获得了整个路径?
  • ...起点和终点在哪里?

标签: c recursion maze


【解决方案1】:

因为@Jackson 链接的问题中没有Dijkstra's algorithm 的解,所以这里有一个修改后的算法适用于这个迷宫问题。我将迷宫值0 视为禁止,将1 作为算法的距离。

看起来neigh() 函数应该是递归的,但事实并非如此,它只是为了以相同的方式检查 4 个邻居。请注意,并非每条路径都被遵循:对于可能是 O(no!) 的大型迷宫。此外,搜索不是定向到终点:遇到终点,算法的这些特征赋予它美丽。

#include <stdio.h>
#include <stdio.h>
#include <limits.h>

#define MSIZE  7                            // matrix/maze dims

enum ntype { virgin, listed, visited };     // for status field

typedef struct {
    int x;                                  // grid position of node
    int y;                                  // grid position of node
    int value;                              // 0 or 1 as defined in maze[][]
    int dist;                               // distance from start node
    int status;                             // enum as above
} node_t;

int maze[MSIZE][MSIZE] =                     // maze definition
  { { 1, 1, 1, 1, 1, 1, 1 },
    { 0, 1, 0, 1, 0, 0, 1 },
    { 0, 1, 0, 1, 1, 1, 1 },
    { 0, 1, 0, 0, 0, 1, 1 },
    { 0, 1, 1, 1, 0, 1, 1 },
    { 0, 0, 1, 0, 1, 1, 1 },
    { 1, 1, 1, 1, 0, 1, 1 } };

node_t node [MSIZE][MSIZE];                 // working array
node_t *list[MSIZE*MSIZE];                  // array of current node pointers
int listlen;                                // num elements in list[]

void neigh(node_t *cptr, int dx, int dy)
// examine one neighbour of node cptr, offset by dx,dy
{
    node_t *nptr;                           // pointer to neighbour
    int dist;                               // accumulated distance from start
    int x = cptr->x + dx;                   // work out neighbour coords
    int y = cptr->y + dy;                   // work out neighbour coords
    if (x < 0 || x >= MSIZE || y < 0 || y >= MSIZE)
        return;                             // failed edge test    
    nptr = &node[y][x];                     // point to neighbour
    if (nptr->value == 0)                   // no-go node
        return;
    if (nptr->status == visited)            // do no re-visit
        return;

    dist = cptr->dist + nptr->value;        // accumulate distance from start
    if (dist < nptr->dist)                  // if it's less than what was known...
        nptr->dist = dist;                  // ...update with the new distance
    if (nptr->status == virgin) {           // if it's never been seen...
        list[listlen++] = nptr;             // ... neighbour to list
        nptr->status = listed;              // and set its status
    }
}

int main(void)
{
    int i, j, smallest, smallind;
    node_t *cptr, *eptr;

    // init the struct array
    for (j=0; j<MSIZE; j++) {
        for (i=0; i<MSIZE; i++) {
            cptr = &node[j][i];             // pointer to the array element
            cptr->value = maze[j][i];       // the maze definition
            cptr->x = i;                    // self's position
            cptr->y = j;                    // self's position
            cptr->dist = INT_MAX;           // distance from start (unknown)
            cptr->status = virgin;          // never examined
        }
    }

    eptr = &node[MSIZE-1][MSIZE-1];         // pointer to end node

    cptr = &node[0][0];                     // pointer to start node
    cptr->dist  = 0;                        // distance of start node from itself!

    // main loop
    while (cptr != eptr) {                  // until we reach the target node
        cptr->status = visited;             // we've been here now
        neigh(cptr,  0, -1);                // examine node above
        neigh(cptr, -1, 0);                 // examine node on left
        neigh(cptr,  1, 0);                 // examine node on right
        neigh(cptr,  0, 1);                 // examine node below

        // find smallest distance of nodes in list[] (won't include virgins)
        smallest = INT_MAX;
        smallind = -1;                      // set invalid marker index
        for (i=0; i<listlen; i++) {
            if (smallest > list[i]->dist) { // compare distance with smallest
                smallest = list[i]->dist;   // remembers the smallest
                smallind = i;               // remembers the list index of smallest
            }
        }
        // take smallest for next time and remove from list
        if(smallind < 0) {                  // -1 was the "marker"
            printf("No route found\n");
            return 1;
        }
        cptr = list[smallind];              // smallest becomes current node
        if (listlen)                        // replace in list with last element...
           list[smallind] = list[--listlen];// ... and reduce list length
    }                                       // now examine this node

    printf("Distance = %d\n", eptr->dist);  // show the distance of the end node
    return 0;
}

程序输出:

Distance = 12

编辑 链接中描述了算法本身,如果它中断,肯定有其他可用的解释。我在代码中添加了更多的 cmets。

我使用 3 个数组,maze[][] 是一个像你一样的简单迷宫定义。然后node[][] 是一个包含运行时数据的struct 数组。我可以直接用迷宫定义来初始化它,但是因为这个程序有一个矩阵大小的硬编码测试数据,以及一个从文件中读取数据的更大矩阵,所以我保持原样。

第三个数组list[] 是一个指向node[][] 元素的指针数组。这就是为什么node[][] 元素在结构本身中包含x,y 坐标:这样我就可以仅从指针中知道位置。当我可以在list[] 中存储一个索引时,我可以使用一维迷宫数组,如果是这样的话,这种复杂性就没有必要了。但我使用了二维数组,只是因为它感觉“更好”。

我很乐意使用指针。在main()// init the struct array 为首的第一个嵌套循环对中,我做的第一件事是创建一个指针,用于设置struct 字段,因为我发现重复使用数组索引很笨拙。所以我写了例如cptr-&gt;x = i;,它与node[j][i].x = i;具有相同的意图。

【讨论】:

  • 天气风向标,因为我们还没有学习到一些你放在这里的sintax,你能用语言描述一下这里发生了什么吗?非常感谢你!
  • @ofersimchovitch 我已经编辑了我的答案以添加一些解释。
【解决方案2】:

从根本上说,这是一个搜索问题。有很多关于如何解决它的好文章,所以我将讨论一些你需要考虑的更好的点。

由于您指定了最短路径,而不仅仅是“相当不错”的路径,因此您需要检查每条可能的路线。我的建议是深度优先搜索。

最明显的是,这是不重复使用的搜索。最短路径将不包含任何循环或光标将返回到它已经存在的位置的任何情况。这使搜索区域保持合理。

【讨论】:

  • 我会在执行过程中将 1 设置为 0,如果路径失败,则在返回时将它们重新设置。
  • Dijkstra 的算法在 不遵循所有可能的路线的情况下工作:这是它美丽的一部分——它不是针对端点,而是遇到它。
【解决方案3】:

如果运行时不是问题,您可以编写一个函数来尝试所有可能的路线,并返回最小值。

int path_helper(int maze[][N],int height, int width, int row, int col){
  if(row==height-1 && col == width-1) return 0;
  if(maze[row][col]==0) return height*width;
  if(col<0 || row<0 || row>=height || col>=width) return height*width;
  maze[row][col]=0;
  int maze2[7][7]={{0}};
  for(int i = 0; i < height; i++){
    for(int j = 0; j < width; j++)
      maze2[j][i]=maze[j][i];
  }
  return min(min(path_helper(maze2,height,width,row+1,col),
  path_helper(maze2,height,width,row-1,col)),      min(path_helper(maze2,height,width,row,col+1),path_helper(maze2,height,width,row,col-1)))+1;
}

它很丑,但它应该可以解决问题

【讨论】:

  • 边缘条件如何?
  • 我没有考虑到这一点。我刚刚修好了。谢谢
  • cemersoz 我试过你的代码,但它溢出了内存堆栈。有什么办法可以解决吗?
  • 代码没有检查循环,所以它可以无限地在两点之间移动。使当前点 0 应该解决它。对不起这个问题
  • 我不知道为什么,由于某种原因它仍然返回 49
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-05
相关资源
最近更新 更多