How to find the fastest route in a maze (in C) [duplicate]

南笙酒味 提交于 2019-11-27 07:25:56

问题


This question already has an answer here:

  • Programming theory: Solve a maze 14 answers

The maze is defined as a square matrix. For example:

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 } };

You can walk only where there's a 1. You can take a step down, up, left, right. You start at the top-left corner and finish at down-right corner.

The output should be the minimum steps to finish any maze. We can assume there is at least one way to finish the maze. i've edited the code and i thought i covered everything.. but obviously i'm missing something. thanks for your help

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));

}


回答1:


Because there is no solution of Dijkstra's algorithm in the question linked by @Jackson, here is a modified algorithm adapted for this maze problem. I take the maze value 0 as no-go, and 1 as the distance for the algorithm.

It looks as though the neigh() function should be recursive, but it is not, it is only there so that 4 neighbours can be examined in the same way. Note that not every path is followed: for a large maze that could be O(no!). Also that the search is not directed to the end point: the end point is encountered, and these features of the algorithm give it its beauty.

#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;
}

Program output:

Distance = 12

EDIT The algorithm itself is described in the link, if it breaks there are sure to be other explanations available. I have added more comments to the code.

I use 3 arrays, maze[][] is a simple maze definition like yours. Then node[][] is an array of struct which hold runtime data. I could have initiliased this with the maze definition directly, but because the program this came from had hard-coded test data of one matrix size, and a bigger matrix with data read from file, I left it as it was.

The third array list[] is an array of pointers to the node[][] elements. This is why node[][] elements contain the x,y coordinates within the struct itself: so that I can know the position from the pointer alone. I could have worked with a 1-D maze array, when I could have stored a single index in list[], if so this complication would not have been necessary. But I used a 2-D array, just because it felt "nicer".

I am comfortable working with pointers. In the first nested loop pair in main() headed // init the struct array the first thing I do is to make a pointer, for use in setting the struct fields, because I find the repeated use of array indexing clumsy. So I write for example cptr->x = i; which has the same intent as node[j][i].x = i;.




回答2:


Fundamentally, this is a search problem. There are lots of well written posts on how to solve it, so I'll talk about a few of the finer points that your will need to consider.

Since you specify want the shortest path, and not just a "pretty good" path, you will need to check every possible route. Depth-first search would be my suggestion.

Most obviously, this is search without reuse. The shortest path will not contain any loops or any case where the cursor will return to a place where it has already been. This keeps the search area reasonable.




回答3:


If runtime is not an issue, you can write a function to try every possible route, and returning the minimum.

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;
}

it's ugly but it should do the trick



来源:https://stackoverflow.com/questions/34256346/how-to-find-the-fastest-route-in-a-maze-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!