迷宫问题
这一题难度中等,两道题都用到的是深度优先遍历,深度优先遍历就是遍历所有结点。
题目
题目链接:https://www.nowcoder.com/questionTerminal/cf24906056f4488c9ddb132f317e03bc
题解
用一个函数去递归探路,走一个标记一个,如果不通就回来,最后输出格式让输出起点到终点,我们就用栈的方式,这样就能保证输出格式。
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef struct Postion
{
int row;//列
int col;//行
}PT;
/
typedef PT STDataType;
typedef struct Stack
{
STDataType* a;//是一个指针指向这个数组
int top;//栈顶
int capacity;//容量
}ST;
//栈需要的接口
// 初始化栈
void StackInit(ST* ps);
// 销毁栈
void StackDestory(ST* ps);
//入栈
void StackPush(ST* ps, STDataType x);
//出栈
void StackPop(ST* ps);
//取栈顶的数据
STDataType StackTop(ST* ps);
//栈的数据个数
int StackSize(ST* ps);
//检测栈是否为空,如果为空返回非零结果,如果非空返回0
bool StackEmpty(ST* ps);//用布尔来判断真假更好用,但是注意引用头文件
void StackInit(ST* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
if (ps->a == NULL)
{
printf("malloc fail\n");
exit(-1);
}
ps->capacity = 4;
ps->top = 0;
}
void StackDestory(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)
{
STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity *= 2;//乘等2才会变成它的二倍
}
}
ps->a[ps->top] = x;
ps->top++;
}
void StackPop(ST* ps)
{
assert(ps);
//栈空了,调用pop,直接中止程序并报错
assert(ps->top > 0);
ps->top--;
}
STDataType StackTop(ST* ps)
{
assert(ps);
//栈空了,调用top,直接中止程序并报错
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int StackSize(ST* ps)
{
assert(ps);
return ps->top;//top所在数组的下标就是栈的长度
}
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;//如果为空返回非零结果,如果不为空返回0
}
ST Path;
/
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(ST* ps)
{
//path数据倒入rpath
ST rPath;
StackInit(&rPath);
while (!StackEmpty(&Path))
{
StackPush(&rPath, StackTop(&Path));//把Path栈顶数据入到rPath这个栈
StackPop(&Path);
}
while (!StackEmpty(&rPath))
{
PT top = StackTop(&rPath);
printf("(%d,%d)\n", top.row, top.col);
StackPop(&rPath);
}
StackDestory(&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;
}
}
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;//next就是下一个可以通的方向
//把我们走过的地方致成2
maze[cur.row][cur.col] = 2;
//假设我们探测的顺序就是上下左右--上就是我们的列加-1;下就是我们的列+1;左就是我们的行-1;右就是我们的行+1;
//上
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);//我们用的是数组指针,所以malloc的要用二级指针,数组指针类型是int*,那么我们返回数组指针的地址自然是int**。动态申请的列
//想要判空就加个判空
for (int i = 0; i < N; ++i)//动态申请的行,并让我们的列(数组指针)连接上
{
maze[i] = (int*)malloc(sizeof(int) * M);//M是列
}
//二维数组的输入(赋值)
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
scanf("%d ", &maze[i][j]);
}
}
StackInit(&Path);
PT entry = { 0, 0 };
//PrintfMaze(maze,N,M);//方便调试的
if (GetMazePath(maze, N, M, entry))
{
//printf("找到通路\n");
PrintPath(&Path);
}
else
{
printf("没有找到通路\n");
}
StackDestory(&Path);
//释放的话同理--先把行释放掉,再释放列,否则会发生内存泄漏
for (int i = 0; i < N; ++i)
{
free(maze[i]);//释放行
}
free(maze);//释放列
maze = NULL;
}
return 0;
}
地下迷宫
地下迷宫是一道滴滴公司曾经的笔试题,难度还是挺高的。
题目
题目链接:https://www.nowcoder.com/questionTerminal/571cfbe764824f03b5c0bfd2eb0a8ddf
题解
将所有通路全部找到,然后比较出最短的一条,输出原理和迷宫问题类似
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<stdbool.h>
typedef struct Postion
{
int row;
int col;
}PT;
/
typedef PT STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST, Stack;
void StackInit(ST* ps);
void StackDestory(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 = (STDataType*)malloc(sizeof(STDataType) * 4);
if (ps->a == NULL)
{
printf("malloc fail\n");
exit(-1);
}
ps->capacity = 4;
ps->top = 0;
}
void StackDestory(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)
{
STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
else
{
ps->a = tmp;
ps->capacity *= 2;
}
}
ps->a[ps->top] = x;
ps->top++;
}
// 出栈
void StackPop(ST* ps)
{
assert(ps);
// 栈空了,调用Pop,直接中止程序报错
assert(ps->top > 0);
//ps->a[ps->top - 1] = 0;
ps->top--;
}
STDataType StackTop(ST* ps)
{
assert(ps);
// 栈空了,调用Top,直接中止程序报错
assert(ps->top > 0);
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;
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 PirntPath(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);
StackDestory(&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;
}
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))
{
StackDestory(&minpath);
StackCopy(&path, &minpath);
}
}
// 探测cur位置得上下左右四个方向
PT next;
maze[cur.row][cur.col] = 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 a[n][m]; // vs2013 不支持
// 动态开辟二维数组
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))
{
PirntPath(&minpath);
}
else
{
printf("Can not escape!\n");
}
StackDestory(&path);
StackDestory(&minpath);
for (int i = 0; i < N; ++i)
{
free(maze[i]);
}
free(maze);
maze = NULL;
}
return 0;
}