【刷题之路Ⅱ】百度面试题——迷宫问题

一、题目描述

原题连接: 迷宫问题
题目描述:
定义一个二维数组 N*M ,如 5 × 5 数组下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。

数据范围:
2≤n,m≤10 , 输入的内容只包含 0≤val≤1

输入描述:

输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。

输出描述:
左上角到右下角的最短路径,格式如样例所示。

示例1

输入
5 5
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出
(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)

示例2

输入
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 1
0 1 1 1 0
0 0 0 0 0
输出
(0,0)
(1,0)
(2,0)
(3,0)
(4,0)
(4,1)
(4,2)
(4,3)
(4,4)

说明
注意:不能斜着走!!

二、解题

1、方法1——暴力递归

解决这道题我采用的是比较暴力的方法,就是将所有的路都走一遍,因为题目只要求求出一条通路,所以只需要直到一条通路就可以结束了。

1.1、思路分析

那我们要怎样设计递归算法呢?
因为题目是要求我们将路径的坐标依次打印出来,所以很容易想到的就是将走过的路径的坐标依次压入栈中,例如:
在这里插入图片描述
只不过最后找到通路后的打印要想将栈中的元素逆置过来再打印。

如果走到某个坐标发现走到了死胡同(上下左右四个方向都走不通),那我们就将当前坐标弹出栈中,返回到上一个坐标继续判断有没有通路。
而为了避免“走回头路”而发生的死递归问题,我们需要将访问过的Maze的坐标的值改成2(其实改成任何数都可以,只要不要改成0就可以):
在这里插入图片描述
然后因为我们要压入栈中的是坐标,所以我们可以定义一个结构体pos,来保存Maze中每个元素对应的横坐标与纵坐标:

typedef struct position {
    int row;
    int col;
} pos;

然后我们就将栈的存储类型改成pos即可。

那我们主要的思路有了,那我们应该怎样设计算法呢?
其实我们主要要实现的只有一个函数——找通路的函数GetPath。
我们在GetPath函数里递归调用上下左右四个方向的找通路,如果当前被调用的坐标等于出口坐标就可以返回,而主要上下左右有任何一个方向的递归调用找到了通路就可以返回(同时最重要的是要先判断坐标的有效性)。

接下来还是看具体的代码实现吧:

1.2、先将栈实现一下

没办法,我用的是C语言,所以还是先要自己造轮子,这其实就只是个CV工程而已:

// 定义一个坐标结构体
typedef struct position {
    int row;
    int col;
} pos;
// 先要将栈实现一下
// 重定义数据类型
typedef pos DataType;

// 定义栈结构
typedef struct stack {
    DataType* data;
    int top;
    int capacity;
} Stack;

// 栈的初始化
void StackInit(Stack* ps);

// 压栈
void StackPush(Stack* ps, DataType x);
// 弹栈
void StackPop(Stack* ps);
// 返回栈顶数据
DataType StackTop(Stack* ps);
// 返回栈的数据个数
int StackSize(Stack* ps);
// 判断栈是否为空
bool StackEmpty(Stack* ps);
// 栈的销毁
void DestroyStack(Stack* ps);

// 栈的初始化
void StackInit(Stack* ps) {
    assert(ps);
    ps->data = NULL;
    ps->top = 0;
    ps->capacity = 0;
}

// 压栈
void StackPush(Stack* ps, DataType x) {
    assert(ps);
    // 检查是否需要增容
    if (ps->top == ps->capacity) {
        int newCapacity = ps->capacity == 0 ? 10 : ps->capacity * 2;
        DataType* temp = (DataType*)realloc(ps->data, newCapacity * sizeof(DataType));
        if (NULL == temp) {
            perror("ralloc fail!\n");
            exit(-1);
        }
        ps->data = temp;
        ps->capacity = newCapacity;
    }
    ps->data[ps->top] = x;
    ps->top++;
}

// 弹栈
void StackPop(Stack* ps) {
    assert(ps);
    assert(ps->top > 0);
    ps->top--;
}

// 返回栈顶数据
DataType StackTop(Stack* ps) {
    assert(ps);
    assert(!StackEmpty(ps));
    return ps->data[ps->top - 1];
}

// 返回栈的数据个数
int StackSize(Stack* ps) {
    assert(ps);
    assert(ps->top >= 0);
    return ps->top;
}

// 判断栈是否为空
bool StackEmpty(Stack* ps) {
    assert(ps);
    return ps->top == 0;
}

// 栈的销毁
void DestroyStack(Stack* ps) {
    assert(ps);
    free(ps->data);
    ps->data = NULL;
    ps->top = 0;
    ps->capacity = 0;
}

1.3、代码实现

因为我们要在多个函数之中使用同一个栈,而每次传参都传一个栈的话就有点太麻烦了。所以我们可以直接将栈定义成全局的。
注意 :因为这里是io型的oj题,所以我们没必要在main函数中最开始就将栈初始化,如果是接口型的oj题,就一定要在main函数中先将栈初始化,不然最多只能过一个测试用例。

// 先定义一个全局栈
Stack pathStack;

main函数:

int main() {
    int Row = 0;
    int Col = 0;
    while (scanf("%d %d", &Row, &Col) != EOF) {
        int** path = (int**)malloc(Row * sizeof(int*));
        if (NULL == path) {
            perror("malloc fail!\n");
            exit(-1);
        }
        int i = 0;
        for (i = 0; i < Row; i++) {
            path[i] = (int*)malloc(Col * sizeof(int));
            if (NULL == path[i]) {
                perror("malloc fail!\n");
                exit(-1);
            }
        }
        int j = 0;
        for (i = 0; i < Row; i++) {
            for (j = 0; j < Col; j++) {
                scanf("%d", &path[i][j]);
            }
        }
        pos entry = { 0 , 0 }; // 入口
        if (GetPath(path, Row, Col, entry)) {
            printPath();
        }
        else {
            printf("没有找到通路\n");
        }
    }
    DestroyStack(&pathStack);
}

找通路函数GetPath:

bool GetPath(int** path, int row, int col, pos cur) {
    assert(path);
    StackPush(&pathStack, cur);
    if (cur.row == row - 1 && cur.col == col - 1) {
        return true;
    }
    path[cur.row][cur.col] = 2;

    // 判断当前坐标的上下左右四个方向是否能走

    pos next = { 0, 0 };

    next = cur;
    // 上
    next.row += 1;
    if (isPass(path, row, col, next)) {
        if (GetPath(path, row, col, next)) {
            return true;
        }
    }

    next = cur;
    // 下
    next.row -= 1;
    if (isPass(path, row, col, next)) {
        if (GetPath(path, row, col, next)) {
            return true;
        }
    }

    next = cur;
    // 左
    next.col -= 1;
    if (isPass(path, row, col, next)) {
        if (GetPath(path, row, col, next)) {
            return true;
        }
    }

    next = cur;
    // 右
    next.col += 1;
    if (isPass(path, row, col, next)) {
        if (GetPath(path, row, col, next)) {
            return true;
        }
    }

    StackPop(&pathStack);
    return false;
}

判断坐标是否能走:

bool isPass(int** path, int row, int col, pos cur) {
    assert(path);
    if ((cur.row >= 0 && cur.row < row)
        && (cur.col >= 0 && cur.col < col)
        && path[cur.row][cur.col] == 0) {
        return true;
    }
    return false;
}

打印通路:

void printPath() {
    Stack RPathStack;
    StackInit(&RPathStack);

    // 将PathStack栈中的数据全都压入RPathStack栈中
    while (!StackEmpty(&pathStack)) {
        StackPush(&RPathStack, StackTop(&pathStack));
        StackPop(&pathStack);
    }

    pos cur = { 0, 0 };
    // 再将RPathStack栈中的数据取出来打印
    while (!StackEmpty(&RPathStack)) {
        cur = StackTop(&RPathStack);
        StackPop(&RPathStack);
        printf("(%d,%d)\n", cur.row, cur.col);
    }
    DestroyStack(&RPathStack);
}```



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用 C 语言实现迷宫问题的完整代码: ```c #include<stdio.h> #include<stdlib.h> #include<conio.h> #define MAX_ROW 5 #define MAX_COL 5 int maze[MAX_ROW][MAX_COL] = { {0, 1, 0, 0, 0}, {0, 1, 0, 1, 0}, {0, 0, 0, 0, 0}, {0, 1, 1, 1, 0}, {0, 0, 0, 1, 0}, }; void print_maze() { int i, j; for (i = 0; i < MAX_ROW; i++) { for (j = 0; j < MAX_COL; j++) { printf("%d ", maze[i][j]); } printf("\n"); } printf("*********\n"); } typedef struct { int row, col; } element; element stack[512]; int top = -1; void push(element item) { stack[++top] = item; } element pop() { return stack[top--]; } int is_empty() { return top == -1; } void path() { int i, row, col, next_row, next_col; element position; maze[0][0] = 2; top = 0; stack[0].row = stack[0].col = 0; while (!is_empty()) { position = pop(); row = position.row; col = position.col; printf("(%d, %d)\n", row, col); if (row == MAX_ROW - 1 && col == MAX_COL - 1) { printf("Path found!\n"); return; } if (col+1 < MAX_COL && maze[row][col+1] == 0) { // right next_row = row; next_col = col+1; maze[next_row][next_col] = 2; position.row = next_row; position.col = next_col; push(position); } if (row+1 < MAX_ROW && maze[row+1][col] == 0) { // down next_row = row+1; next_col = col; maze[next_row][next_col] = 2; position.row = next_row; position.col = next_col; push(position); } if (col-1 >= 0 && maze[row][col-1] == 0) { // left next_row = row; next_col = col-1; maze[next_row][next_col] = 2; position.row = next_row; position.col = next_col; push(position); } if (row-1 >= 0 && maze[row-1][col] == 0) { // up next_row = row-1; next_col = col; maze[next_row][next_col] = 2; position.row = next_row; position.col = next_col; push(position); } print_maze(); } printf("Path not found\n"); } int main() { path(); return 0; } ``` 在上述代码中,我们定义了一个 `maze` 数组来表示迷宫,0 表示可以通过的路,1 表示障碍物,2 表示走过的路程。我们使用栈来记录已经走过的路径,并通过 `push()` 和 `pop()` 操作来实现栈的基本功能。在 `path()` 函数中,我们从起点开始遍历迷宫,如果找到了终点,则输出 "Path found!",否则输出 "Path not found"。 我们可以通过调用 `print_maze()` 函数来输出迷宫的状态,以及调用 `path()` 函数来寻找迷宫的路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林先生-1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值