简体   繁体   English

解决迷宫回溯

[英]Solve a maze backtracking

I am trying to solve a maze using backtracking in C. To solve the maze the following rules:我正在尝试使用 C 中的回溯解决迷宫。要解决迷宫,请遵循以下规则:

  • You begin from the position of S and need to go towards E你从S的位置开始,需要走向E
  • You can only go on '.'你只能继续'.' path小路
  • Convert all the '.'转换所有的'.' into '#' including S and E进入“#”,包括 S 和 E

The input consists of amxn matrix: Input example:输入由 amxn 矩阵组成: 输入示例:

11 11
+-+-+-+-+-+
S.|...|...|
+.+.+.+-+.+
|.|.|.....|
+.+-+-+-+.+
|...|.|...|
+.+.+.+.+-+
|.|...|.|.|
+.+-+.+.+.+
|...|.....E
+-+-+-+-+-+

Expected solution :预期的解决方案:

+-+-+-+-+-+
##|...|...|
+#+.+.+-+.+
|#|.|.....|
+#+-+-+-+.+
|###|.|...|
+.+#+.+.+-+
|.|###|.|.|
+.+-+#+.+.+
|...|######
+-+-+-+-+-+

I am trying really hard to solve it but for some reason my program doesn't go back once I reached a point in the maze from where I can't go further.It just go in all the directions where it sees a '.'我真的很努力地试图解决它,但由于某种原因,一旦我到达迷宫中的某个点,我就无法再继续下去,我的程序就不会返回。它只是朝着它看到“。”的所有方向前进。

My idea was to start from the position of S and using at each recursion step the old position that we were.我的想法是从 S 的位置开始,并在每个递归步骤中使用我们所在的旧位置。 I will go in all the direction from the position where I am standing if the position that I am looking at is a '.'如果我正在看的位置是“.”,我将从我站立的位置向所有方向走。 and if that point was not my old position.如果那一点不是我的旧立场。

I also think that I have a problem when i reach a point where it was a crossroad when I backtrack.我也认为当我到达一个十字路口时我有一个问题,当我回溯时。 For example:例如:

+-+-+-+-+-+
##|...|...|
+#+.+.+-+.+
|#|.|.....|
+#+-+-+-+.+
|0##|.|...|
+.+#+.+.+-+
|.|###|.|.|
+.+-+#+.+.+
|..1|######
+-+-+-+-+-+

Imagine that I am in the position 0. And I backtracked from 1 changing back the # into '.'.How can I make a statement saying that you have 2 # possibilities to go back , yet you should stop?想象一下,我在位置 0。我从 1 回溯,将 # 改回 '.'。我怎么能声明说你有 2 # 种返回的可能性,但你应该停下来?

My code :我的代码:

#include <stdio.h>
#include <stdlib.h>

void *safeMalloc(int n) {
    void *p = malloc(n);
    if (p == NULL) {
        printf("Error: malloc(%d) failed. Out of memory?\n", n);
        exit(EXIT_FAILURE);
    }
    return p;
}


char ** readMatrix(int m,int n,int* startI,int* startJ,int* endI,int* endJ){
    char **arr = safeMalloc(m*sizeof(char *));
    int row;
    for (row=0; row < m; row++) {
        arr[row] = safeMalloc(n*sizeof(char));
    }
    int i,j;
    for(i=0;i<m;i++){
        for(j=0;j<m;j++){
            scanf(" %c",&arr[i][j]);
            if(arr[i][j]=='S'){
                *startI=i;
                *startJ=j;
            }
            if(arr[i][j]=='E'){
                *endI=i;
                *endJ=j;
            }
        }
        getchar();
    }

    return arr;
}

void printNumber(char **arr,int m,int n){
    int i,j;
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            printf("%c", arr[i][j]);
        }
        printf("\n");
    }
}

void findPath(char** arr,int m,int n,int startI,int startJ,int endI,int endJ,int oldI,int oldJ){
    int i=startI,j=startJ;
    int stepsPossible=4;
            //going up
           if(i-1>=0){
                if((arr[i-1][j]=='.') && ((i-1!=oldI) || (j!=oldJ))){
                    arr[i][j]='#';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i-1,j,endI,endJ,oldI,oldJ);
                }else{
                    stepsPossible--;
                }
           }
           //going right

           if(j+1<n){
                if((arr[i][j+1]=='.') && ((i!= oldI) || (j+1!=oldJ))){
                    arr[i][j]='#';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i,j+1,endI,endJ,oldI,oldJ);
                }else{
                    stepsPossible--;
                }
           }
           //going left
           if(j-1>=0){
                if((arr[i][j-1]=='.') && ((i!= oldI) || (j-1!=oldJ))){
                    arr[i][j]='#';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i,j-1,endI,endJ,oldI,oldJ);
                }else{
                    stepsPossible--;
                }
           }

           //going down
            if(i+1<m){
                if((arr[i+1][j]=='.') && ((i+1!= oldI) || (j!=oldJ))){
                    arr[i][j]='#';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i+1,j,endI,endJ,oldI,oldJ);
                }else{
                    stepsPossible--;
                }
           }
        //if the next block is E then we can stop.
           if((arr[i-1][j]=='E') || (arr[i][j+1]=='E') || (arr[i][j-1]=='E') || (arr[i+1][j]=='E')){
                if(arr[i-1][j]=='E'){
                    arr[i-1][j]='#';
                }

                if(arr[i][j+1]=='E'){
                    arr[i][j+1]='#';
                }

                if(arr[i][j-1]=='E'){
                    arr[i][j-1]='#';
                }

                if(arr[i+1][j]=='E'){
                    arr[i+1][j]='#';
                }
                return;
            }


            if(stepsPossible==0){
                if(arr[i-1][j]=='#'){
                    arr[i][j]='.';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i-1,j,endI,endJ,oldI,oldJ);
                }else{
                    return;
                }

                if(arr[i][j+1]=='#' ){
                    arr[i][j]='.';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i,j+1,endI,endJ,oldI,oldJ);
                }else{
                    return;
                }

                if(arr[i][j-1]=='#' ){
                    arr[i][j]='.';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i,j-1,endI,endJ,oldI,oldJ);
                }else{
                    return;
                }

                if(arr[i+1][j]=='#' ){
                    arr[i][j]='.';
                    oldI=i;
                    oldJ=j;
                    findPath(arr,m,n,i+1,j,endI,endJ,oldI,oldJ);
                }else{
                    return;
                }
            }
}


int main()
{
    int m,n;
    scanf("%d %d",&m,&n);
    int startI,startJ,endI,endJ;
    char** arr;
    arr=readMatrix(m,n,&startI,&startJ,&endI,&endJ);
    findPath(arr,m,n,startI,startJ,endI,endJ,startI,startJ);
    printNumber(arr,m,n);
    return 0;
}

I would suggest to use BFS because我建议使用 BFS 因为

  • BFS will find the shortest solution. BFS 会找到最短的解决方案。
  • DFS handles certain mazes very very poorly. DFS 处理某些迷宫的能力非常差。

Here is short description of BFS for your case:以下是针对您的案例的 BFS 的简短描述:

  1. Find 'S' in your maze and add it into queue在迷宫中找到“S”并将其添加到队列中
  2. While queue is not empty check get element from queue.当队列不为空时,检查从队列中获取元素。 Replace element with "#".用“#”替换元素。 If element is E, you are done.如果元素是 E,你就完成了。 Check neighbours(up, down, left right) of the element, if they are ".", then add into queue.检查元素的邻居(上,下,左),如果他们是“。”,然后加入队列。
  3. If queue is empty and E not found, then there is no direct path from S to E如果队列为空且未找到 E,则没有从 S 到 E 的直接路径

Make proper use of the return value, as you can utilize it to simplify your logic.正确使用返回值,因为您可以利用它来简化您的逻辑。 Choose different return values on findPath for the error case (backtracking necessary) and the success case (end reached).findPath为错误情况(需要回溯)和成功情况(到达终点)选择不同的返回值。

Now you can put setting the # unconditionally in the start of that function, and resetting back to .现在,您可以将#无条件地设置在该函数的开头,然后重新设置回. unconditionally in the end for the backtracking case.无条件地在回溯的情况下结束。

There is no need to count possible directions either, only checking if some call returned success.也不需要计算可能的方向,只检查某个调用是否返回成功。

Also no need to write the boundary checks over and over again, if you just check them at the start of the function you can just pass invalid coordinates without any issues.也无需一遍又一遍地编写边界检查,如果您只是在函数开始时检查它们,则可以传递无效坐标而不会出现任何问题。

bool findPath(char** arr, size_t sx, size_t sy, int x, int y) {
    if (x < 0 || x >= sx || y < 0 || y >= sy) return false;
    if (arr[x][y] == 'E') {
        are[x][y] = '#';
        return true;
    }
    if (arr[x][y] != '.') return false;
    arr[x][y] = '#';
    bool success = findPath(arr, sx, sy, x-1, y) ||
        findPath(arr, sx, sy, x+1, y) ||
        findPath(arr, sx, sy, x, y-1) ||
        findPath(arr, sx, sy, x, y+1);
    if (!success) arr[x][y] = '.';
    return success;
}

Implementations for backtracking algorithms usually all follow the same pattern:回溯算法的实现通常都遵循相同的模式:

  1. Try to either trivially reject or accept the current solution.尝试简单地拒绝或接受当前的解决方案。
  2. Modify the current solution.修改当前解决方案。
  3. Try variations.尝试变化。
  4. Clean up the modifications if not successful.如果不成功,请清理修改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM