数据结构--迷宫问题
1. 迷宫问题求解
迷宫问题_牛客题霸_牛客网
以上迷宫OJ题曾经是百度某一年的其中一个笔试题,迷宫问题本质就是一个图的遍历问题,从起点开始不断四个方向探索,直到走到出口,走的过程中我们借助栈记录走过路径的坐标,栈记录坐标有两方面的作用,一方面是记录走过的路径,一方面方便走到死路时进行回溯找其他的通路。
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
// 迷宫坐标结构
typedef struct Position {
int row; // 行
int col; // 列
}PT;
typedef PT STDataType;
// 栈的结构--建议使用数组
typedef struct Stack {
STDataType* a;
int top; // 栈顶
int capacity;
}ST, Stack;
//typedef struct Stack ST;
// 初始化栈
void StackInit(ST* ps);
// 销毁栈
void StackDestroy(ST* ps);
// 入栈
void StackPush(ST* ps, STDataType x);
// 出栈
void StackPop(ST* ps);
// 取栈顶元素
STDataType StackTop(ST* ps);
// 获取栈中有效元素个数
int StackSize(ST* ps);
// 判断栈是否为空
bool StackEmpty(ST* ps);
// 初始化栈
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
// 销毁栈
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
// 入栈
void StackPush(ST* ps, STDataType x)
{
assert(ps);
// 插入数据之前先检查空间是否足够
if (ps->top == ps->capacity)
{
// 空间不够增容
int new_capacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * new_capacity);
if (tmp == NULL)
{
perror("realloc fail!\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = new_capacity;
}
ps->a[ps->top++] = x;
}
// 出栈
void StackPop(ST* ps)
{
assert(ps);
// 栈不能为空
assert(!StackEmpty(ps));
--ps->top;
}
// 取栈顶元素
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
// 获取栈中有效元素个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
// 判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
Stack path; // 路径
/********************************************************/
/* 迷宫问题https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc */
// 示例
/*
输入:
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)
输入:
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)
*/
// 打印迷宫
void PrintMaze(int** maze, int N, int M)
{
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%d ", maze[i][j]);
}
printf("\n");
}
printf("\n");
}
// 输出栈里面的坐标路径
void PrintPath(Stack* ps)
{
// path里面的数据倒入rPath
Stack rPath;
StackInit(&rPath);
while (!StackEmpty(ps))
{
StackPush(&rPath, StackTop(ps));
StackPop(ps);
}
while (!StackEmpty(&rPath))
{
PT top = StackTop(&rPath);
printf("(%d,%d)\n", top.row, top.col);
StackPop(&rPath);
}
StackDestroy(&rPath);
}
// 可以通过的位置
bool IsPass(int** maze, int N, int M, PT pos)
{
if (pos.row >= 0 && pos.row < N
&& pos.col >= 0 && pos.col < M
&& maze[pos.row][pos.col] == 0)
{
return true;
}
else
{
return false;
}
}
// 路径逻辑函数--N,M行数和列数,cur当前位置
bool GetMazePath(int** maze, int N, int M, PT cur)
{
StackPush(&path, cur);
// 如果走到出口
if (cur.row == N - 1 && cur.col == M - 1)
return true;
// 探测cur位置的上下左右四个方向
PT next; // 定义下一个位置
maze[cur.row][cur.col] = 2; // 走过一个格子就把数置为2,也可以不置
// 上
next = cur;
next.row -= 1;
if (IsPass(maze, N, M, next))
{
if (GetMazePath(maze, N, M, next))
return true;
}
// 下
next = cur;
next.row += 1;
if (IsPass(maze, N, M, next))
{
if (GetMazePath(maze, N, M, next))
return true;
}
// 左
next = cur;
next.col -= 1;
if (IsPass(maze, N, M, next))
{
if (GetMazePath(maze, N, M, next))
return true;
}
// 右
next = cur;
next.col += 1;
if (IsPass(maze, N, M, next))
{
if (GetMazePath(maze, N, M, next))
return true;
}
StackPop(&path);
return false;
}
int main()
{
int N = 0, M = 0;
while (scanf("%d %d", &N, &M) != EOF)
{
// 动态开辟二维数组
int** maze = (int**)malloc(sizeof(int*) * N);
for (int i = 0; i < N; ++i)
{
maze[i] = (int*)malloc(sizeof(int) * M);
}
// 二维数组输入
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
scanf("%d", &maze[i][j]);
}
}
StackInit(&path);
// 测试打印迷宫
//PrintMaze(maze, N, M);
PT entry = { 0, 0 }; // 入口
if (GetMazePath(maze, N, M, entry))
{
//printf("找到通路!\n");
PrintPath(&path);
}
else
{
printf("没有找到通路!\n");
}
StackDestroy(&path);
for (int i = 0; i < N; ++i)
{
free(maze[i]); // 先free每一行
}
free(maze); // 再free整个maze
maze = NULL;
}
return 0;
}
2. 迷宫最短路径求解
地下迷宫_滴滴笔试题_牛客网
本题在曾经是滴滴某一年的笔试题,本题在上一个题的基础上计入了体力值的概念,但是本题还有一个隐藏条件,就是要找出迷宫的最短路径,如下图的两个测试用例,需要找出最短路径,才能通过全部测试用例。
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
// 迷宫坐标结构
typedef struct Position {
int row; // 行
int col; // 列
}PT;
typedef PT STDataType;
// 栈的结构--建议使用数组
typedef struct Stack {
STDataType* a;
int top; // 栈顶
int capacity;
}ST, Stack;
//typedef struct Stack ST;
// 初始化栈
void StackInit(ST* ps);
// 销毁栈
void StackDestroy(ST* ps);
// 入栈
void StackPush(ST* ps, STDataType x);
// 出栈
void StackPop(ST* ps);
// 取栈顶元素
STDataType StackTop(ST* ps);
// 获取栈中有效元素个数
int StackSize(ST* ps);
// 判断栈是否为空
bool StackEmpty(ST* ps);
// 初始化栈
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
// 销毁栈
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
// 入栈
void StackPush(ST* ps, STDataType x)
{
assert(ps);
// 插入数据之前先检查空间是否足够
if (ps->top == ps->capacity)
{
// 空间不够增容
int new_capacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * new_capacity);
if (tmp == NULL)
{
perror("realloc fail!\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = new_capacity;
}
ps->a[ps->top++] = x;
}
// 出栈
void StackPop(ST* ps)
{
assert(ps);
// 栈不能为空
assert(!StackEmpty(ps));
--ps->top;
}
// 取栈顶元素
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->a[ps->top - 1];
}
// 获取栈中有效元素个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
// 判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
Stack path; // 路径
Stack minpath; // 最短路径
/********************************************************/
/* 迷宫问题https://www.nowcoder.com/questionTerminal/571cfbe764824f03b5c0bfd2eb0a8ddf */
// 打印迷宫
void PrintMaze(int** maze, int N, int M)
{
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
printf("%d ", maze[i][j]);
}
printf("\n");
}
printf("\n");
}
// 输出栈里面的坐标路径
void PrintPath(Stack* ps)
{
// path里面的数据倒入rPath
Stack rPath;
StackInit(&rPath);
while (!StackEmpty(ps))
{
StackPush(&rPath, StackTop(ps));
StackPop(ps);
}
while (StackSize(&rPath) > 1)
{
PT top = StackTop(&rPath);
printf("[%d,%d],", top.row, top.col);
StackPop(&rPath);
}
// 最后一次单独打印
PT top = StackTop(&rPath);
printf("[%d,%d]", top.row, top.col);
StackPop(&rPath);
StackDestroy(&rPath);
}
// 可以通过的位置
bool IsPass(int** maze, int N, int M, PT pos)
{
if (pos.row >= 0 && pos.row < N
&& pos.col >= 0 && pos.col < M
&& maze[pos.row][pos.col] == 1)
{
return true;
}
else
{
return false;
}
}
// 深拷贝
void StackCopy(Stack* ppath, Stack* pcopy)
{
pcopy->a = (STDataType*)malloc(sizeof(STDataType) * ppath->capacity);
memcpy(pcopy->a, ppath->a, sizeof(STDataType) * ppath->top);
pcopy->top = ppath->top;
pcopy->capacity = ppath->capacity;
}
// 路径逻辑函数--N,M行数和列数,cur当前位置 P体力
void GetMazePath(int** maze, int N, int M, PT cur, int P)
{
StackPush(&path, cur);
// 如果走到出口
if (cur.row == 0 && cur.col == M - 1)
{
// 找到了更短的路径,更新minpath
if (P >= 0 && StackEmpty(&minpath)
|| StackSize(&path) < StackSize(&minpath))
{
StackDestroy(&minpath);
StackCopy(&path, &minpath);
}
}
// 探测cur位置的上下左右四个方向
PT next; // 定义下一个位置
maze[cur.row][cur.col] = 2; // 走过一个格子就把数置为2
// 上
next = cur;
next.row -= 1;
if (IsPass(maze, N, M, next))
{
// 一直递归找最短路径
GetMazePath(maze, N, M, next, P - 3);
}
// 下
next = cur;
next.row += 1;
if (IsPass(maze, N, M, next))
{
GetMazePath(maze, N, M, next, P);
}
// 左
next = cur;
next.col -= 1;
if (IsPass(maze, N, M, next))
{
GetMazePath(maze, N, M, next, P - 1);
}
// 右
next = cur;
next.col += 1;
if (IsPass(maze, N, M, next))
{
GetMazePath(maze, N, M, next, P - 1);
}
// 恢复一下
maze[cur.row][cur.col] = 1;
StackPop(&path);
}
int main()
{
int N = 0, M = 0, P = 0;
while (scanf("%d %d %d", &N, &M, &P) != EOF)
{
// 动态开辟二维数组
int** maze = (int**)malloc(sizeof(int*) * N);
for (int i = 0; i < N; ++i)
{
maze[i] = (int*)malloc(sizeof(int) * M);
}
// 二维数组输入
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
scanf("%d", &maze[i][j]);
}
}
StackInit(&path);
StackInit(&minpath);
// 测试打印迷宫
//PrintMaze(maze, N, M);
PT entry = { 0, 0 }; // 入口
GetMazePath(maze, N, M, entry, P);
if (!StackEmpty(&minpath))
{
PrintPath(&minpath);
}
else
{
printf("Can not escape!\n");
}
StackDestroy(&path);
StackDestroy(&minpath);
for (int i = 0; i < N; ++i)
{
free(maze[i]); // 先free每一行
}
free(maze); // 再free整个maze
maze = NULL;
}
return 0;
}
完