每日一题——迷宫问题(I)

简介: 每日一题——迷宫问题(I)

迷宫问题——I

题目链接

思路

创建二维数组,并实现输入

首先输入二维数组的行和列:

int n, m;
scanf("%d%d", &n, &m);

然后动态开辟二维数组:

注:对动态开辟还不太了解的同学可以看看👉C语言——动态内存管理

int** nums = (int**)malloc(sizeof(int*) * n);
for (int i = 0; i < n; i++)
{
    nums[i] = (int*)malloc(sizeof(int) * m);
}

最后向二维数组输入数据,形成迷宫

for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
        scanf("%d", &nums[i][j]);

实现找路(FindWay)

首先,为了方便记录,我们可以定义一个结构体来记录二维数组每一个位置的坐标

注:对结构体操作不太了解的小伙伴看这里👉传送门

typedef struct Position
{
  int row;
  int col;
}POS;

接着,我们应该确定找路的整体思路

  1. 从上、下、左、右四个方向分别探路
  2. 探路之前,要对将要前进到区域进行有效性判断,如果符合条件再前进,否则选择下一个方向
  3. 如果,四个方向都无法前进,那么说明是个死路,就要进行回溯,由此,可以推出,需要用递归算法实现
  4. 由回溯的位置再次选择方向前进,为了避免走相同的路,我们应该在走过的每个点位做上标记,例如修改为除0,1的数据

判断位置有效性(Judge):

bool Judge(int** nums, int n, int m, POS pos)
{
    /*
      如果数组越界
      或者该点位的数据不是0
      就说明该点位无效,不能前进
    */
  if (pos.col >= m || pos.col < 0 ||
    pos.row >= n || pos.row < 0 ||
    nums[pos.row][pos.col] != 0)
  {
    return false;
  }
  else
    return true;
}

FindWay主体:

FindWay(int** nums, int n, int m, POS entry)
{
  nums[entry.row][entry.col] = -1;
  //上
  POS next = entry;
  next.row--;
  if (Judge(nums, n, m, next))
  {
    FindWay(nums, n, m, next)
  }
  //下
  next = entry;
  next.row++;
  if (Judge(nums, n, m, next))
  {
    FindWay(nums, n, m, next)
  }
  //左
  next = entry;
  next.col--;
  if (Judge(nums, n, m, next))
  {
    FindWay(nums, n, m, next)
  }
  //右
  next = entry;
  next.col++;
  if (Judge(nums, n, m, next))
  {
    FindWay(nums, n, m, next)
  }
}

这样写会造成一个问题:经过调试我们可以发现,这个函数并没有实现走到右下角(出口)便结束的功能,这个函数结束时,停留的位置会在出口处(因为可以走的的地方全部被标记为-1,当无路可走的时候就会回溯,最后就会回到出口),因此,我们可以将FindWay()函数的返回值设定为bood类型,当走到出口时就退出函数:

bool FindWay(int** nums, int n, int m, POS entry)
{
  if(entry.row == n - 1 && entry.col == m - 1)
    return true;
  nums[entry.row][entry.col] = -1;
  //上
  POS next = entry;
  next.row--;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true;
  }
  //下
  next = entry;
  next.row++;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true;
  }
  //左
  next = entry;
  next.col--;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true; 
  }
  //右
  next = entry;
  next.col++;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true;
  }
  return false;
}

保存正确的路径

很容易想到,我们可以用一个数组来保存我们每走过的下标位置。但是当我们进行回溯的时候又要不断对无效的路径进行删除,可见只是单纯的用一个数组是不方便实现的。

我们可以用栈的“先入后出”的特性来实现

注:对于栈的基本操作还不太熟悉的小伙伴可以看看👉栈的基本操作

  • 每走到一个位置,就将这个位置入栈
  • 如果走到的位置无法前进,就说明这个点位是思路,需要回溯,每回溯一个点位,就需要将这个点位删除(出栈)
bool FindWay(int** nums, int n, int m, POS entry)
{
  StackPush(&STACK, entry);
  if(entry.row == n - 1 && entry.col == m - 1)
    return true;
  nums[entry.row][entry.col] = -1;
  //上
  POS next = entry;
  next.row--;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true;
  }
  //下
  next = entry;
  next.row++;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true;
  }
  //左
  next = entry;
  next.col--;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true; 
  }
  //右
  next = entry;
  next.col++;
  if (Judge(nums, n, m, next))
  {
    if (FindWay(nums, n, m, next))
      return true;
  }
  StackPop(&STACK);
  return false;
}

打印路径

由于栈的“先入后出”的特性,取出栈的数据只能从栈顶到栈底取,因此如果我们直接对栈的数据进行打印,那么这个路径就是倒序(出口->入口)的。

为了得到正序(入口->出口)的路径,我们可以建立一个辅助栈,先将原有栈的数据逐个出栈到辅助栈中,再打印辅助栈的数据,这样就可以做到正序打印路径了。

void PrintWay()
{
  ST* stack = (ST*)malloc(sizeof(ST));
  StackInit(stack);
  while (!StackEmpty(&STACK))
  {
    POS temp = StackTop(&STACK);
    StackPop(&STACK);
    StackPush(stack, temp);
  }
  while (!StackEmpty(stack))
  {
    POS temp = StackTop(stack);
    StackPop(stack);
    printf("(%d,%d)\n", temp.row, temp.col);
  }
}

实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
typedef struct Position
{
  int row;
  int col;
}POS;
typedef POS StackDataType;
typedef struct Stack
{
  StackDataType* data;
  int top;
}ST;
ST STACK; //定义一个全局栈
//初始化栈
void StackInit(ST* stack)
{
  stack->top = 0;
  stack->data = (POS*)malloc(sizeof(POS) * 100);
}
//判断栈空
bool StackEmpty(ST* stack)
{
  return stack->top == 0;
}
//入栈
void StackPush(ST* stack, POS val)
{
  stack->data[(stack->top)++] = val;
}
//出栈
void StackPop(ST* stack)
{
  assert(!StackEmpty(stack));
  stack->top--;
}
//返回栈顶元素
StackDataType StackTop(ST* stack)
{
  return stack->data[stack->top - 1];
}
//判断是否可以前进
bool Judge(int** nums, int n, int m, POS pos)
{
  if (pos.col >= m || pos.col < 0 ||
    pos.row >= n || pos.row < 0 ||
    nums[pos.row][pos.col] != 0)
  {
    return false;
  }
  else
    return true;
}
//找路
bool FindWay(int** nums, int n, int m, POS entry)
{
    //先将该位置入栈
  StackPush(&STACK, entry);
    //判断是否已经到了出口
  if(entry.row == n - 1 && entry.col == m - 1)
    return true;
    //为了防止走相同的路,要对走过的路做标记
  nums[entry.row][entry.col] = -1;
  //上
  POS next = entry;
  next.row--;
  if (Judge(nums, n, m, next))
  {
        //如果到了出口,直接返回
    if (FindWay(nums, n, m, next))
      return true;
  }
  //下
  next = entry;
  next.row++;
  if (Judge(nums, n, m, next))
  {
        //如果到了出口,直接返回
    if (FindWay(nums, n, m, next))
      return true;
  }
  //左
  next = entry;
  next.col--;
  if (Judge(nums, n, m, next))
  {
        //如果到了出口,直接返回        
    if (FindWay(nums, n, m, next))
      return true; 
  }
  //右
  next = entry;
  next.col++;
  if (Judge(nums, n, m, next))
  {
        //如果到了出口,直接返回        
    if (FindWay(nums, n, m, next))
      return true;
  }
    //如果是死路,就出栈,并返回假,说明没到出口
  StackPop(&STACK);
  return false;
}
void PrintWay()
{
    //创建一个辅助栈
  ST* stack = (ST*)malloc(sizeof(ST));
  StackInit(stack);
    //将原始栈的数据放入辅助栈
  while (!StackEmpty(&STACK))
  {
    POS temp = StackTop(&STACK);
    StackPop(&STACK);
    StackPush(stack, temp);
  }
    //打印辅助栈的路径
  while (!StackEmpty(stack))
  {
    POS temp = StackTop(stack);
    StackPop(stack);
    printf("(%d,%d)\n", temp.row, temp.col);
  }
}
int main()
{
  int n, m;
  scanf("%d%d", &n, &m);
    //动态申请二维数组
  int** nums = (int**)malloc(sizeof(int*) * n);
  for (int i = 0; i < n; i++)
  {
    nums[i] = (int*)malloc(sizeof(int) * m);
  }
    //输入
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
      scanf("%d", &nums[i][j]);
    //初始化全局栈
  StackInit(&STACK);
    //找路
  POS entry = { 0,0 };
  FindWay(nums, n, m, entry);
    //打印路径
  PrintWay();
  return 0;
}
相关文章
|
10月前
|
算法
蓝桥杯:真题 迷宫
蓝桥杯:真题 迷宫
47 0
|
2月前
|
存储
每日一题——地下迷宫(迷宫问题II)
每日一题——地下迷宫(迷宫问题II)
|
2月前
|
机器学习/深度学习 存储
leetcode-1036:逃离大迷宫
leetcode-1036:逃离大迷宫
24 0
|
12月前
《蓝桥杯每日一题》递推·AcWing 3777. 砖块
《蓝桥杯每日一题》递推·AcWing 3777. 砖块
57 0
洛谷P1605:迷宫
洛谷P1605:迷宫
57 0
洛谷 P1141 01迷宫
洛谷 P1141 01迷宫
60 0
|
存储
每日一题——螺旋矩阵
每日一题——螺旋矩阵
|
算法 定位技术 C++
【兔年之兔子走迷宫】 用一个小游戏对回溯法进行实现 | C++
简单的来说,算法就是用计算机程序代码来实现数学思想的一种方法。学习算法就是为了了解它们在计算机中如何演算,以及在当今的信息时代,它们是如何在各个层面上影响我们的日常生活的,从而提高我们的逻辑思维能力和处理实际问题的能力。善用算法、巧用算法,是培养程序设计逻辑的重中之重,许多实际的问题都可用多个可行的算法来解决, 但是要从中找出最优的解决算法却是一项挑战。
508 6
【兔年之兔子走迷宫】 用一个小游戏对回溯法进行实现 | C++
|
算法 C语言 索引
蓝桥杯 迷宫 二叉树 真题
蓝桥杯 迷宫 二叉树 真题
75 0
蓝桥杯 迷宫 二叉树 真题