迷宫问题 -- 深度优先搜索算法DFS

以下部分内容来自于B站视频 – 麦克老师讲算法

视频链接:https://www.bilibili.com/video/BV1bK4y1C7W2?p=2&spm_id_from=pageDriver.

迷宫示例图像如下:
在这里插入图片描述
程序实现使用了递归思想,没有用到堆栈知识。
在这里插入图片描述
实现的代码:

#include <iostream>
using namespace std;

/*
 * 由于这里使用数组的原因, 而数组的初始值是为0的,
 * 所以不能让 0 表示空地, 1 表示障碍物。
 * 这里用 1 表示空地, 2 表示障碍物。
 */

int start_x, start_y; //起点坐标:(start_x, start_y)
int end_x, end_y; //终点坐标:(endx, endy)

int min_step = 99999;//一开始给它一个很大的数

//地图,放100行100列
int map[100][100];//1表示空地,2表示障碍物
int visit[100][100];//1表示访问,0表示未访问

void dfs(int x,int y,int step)
{
	if (x== end_x && y== end_y)
	{
		//如果当前步数小于最小值,就更新
		if (step < min_step)
			min_step = step;
		return;//回溯
	}
	//顺时针试探
	//右
	//如果当前位置的右边为空地且没有访问过
	if (map[x][y + 1] == 1 && visit[x][y + 1] == 0)
	{
		//将右边的点设置为已访问
		visit[x][y + 1] = 1;
		dfs(x, y + 1, step + 1);
		visit[x][y + 1] = 0;
	}

	//下
	if (map[x+1][y] == 1 && visit[x+1][y] == 0)
	{
		//将下边的点设置为已访问
		visit[x+1][y] = 1;
		dfs(x + 1, y, step + 1);
		visit[x+1][y] = 0;
	}
	//左
	if (map[x][y - 1] == 1 && visit[x][y - 1] == 0)
	{
		//将左边的点设置为已访问
		visit[x][y - 1] = 1;
		dfs(x, y - 1, step + 1);
		visit[x][y - 1] = 0;
	}
	//上
	if (map[x-1][y] == 1 && visit[x-1][y] == 0)
	{
		//将上边的点设置为已访问
		visit[x-1][y] = 1;
		dfs(x-1, y, step + 1);
		visit[x-1][y] = 0;
	}
	return;
}

int main()
{
	int m, n;

	printf("请设置地图的行数和列数,以逗号分隔:\n");
	scanf("%d,%d",&m,&n);

	printf("请输入 %d 行 %d 列的地图:\n",m,n);
	for (int i=1;i<=m;i++)
	{ 
		for (int j = 1; j <= n; j++)
			scanf("%d",&map[i][j]);//0表示空地,1表示障碍物
	}
	
	printf("请输入起点坐标,以逗号分隔:\n");
	scanf("%d,%d", &start_x,&start_y);

	printf("请输入终点坐标,以逗号分隔:\n");
	scanf("%d,%d", &end_x, &end_y);

	visit[start_x][start_y] = 1;
	dfs(start_x, start_y,0);
	printf("最短步数为 %d 步.\n", min_step);
	
	system("pause");
	return 0;
}

测试数据如下:逗号为英文字符,可以在记事本中一起直接复制粘贴。
在这里插入图片描述
在这里插入图片描述
上述代码还有优化的地方。
在这里插入图片描述

//定义方向数组
int dx[4] = { 0,1,0,-1 };
int dy[4] = { 1,0,-1,0 };

void dfs(int x,int y,int step)
{
	if (x== end_x && y== end_y)
	{
		//如果当前步数小于最小值,就更新
		if (step < min_step)
			min_step = step;
		return;//回溯
	}
	//顺时针试探
	for (int k = 0; k < 4; k++)
	{
		//tx,ty表示下一个方向的试探坐标
		int tx, ty;
		tx = x + dx[k];
		ty = y + dy[k];
		if (map[tx][ty]==1&& visit[tx][ty]==0)
		{
			visit[tx][ty] = 1;
			dfs(tx, ty, step + 1);
			visit[tx][ty] = 0;
		}
	}
	return;
}

以下部分内容来自于B站视频 – 懒猫老师-数据结构-(8)栈的应用:迷宫问题(DFS)

视频链接:https://www.bilibili.com/video/BV1oE41177wk?spm_id_from=333.999.0.0.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
M+2和N+2表示的是围墙的两行和两列。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里走的迷宫遵循的都是顺时针原则:即 右-下-左-上 的原则。
在这里插入图片描述
最原汁原味版的迷宫程序
stack.h

#ifndef _STACK_H_
#define _STACK_H_

#include "maze.h"

const int MAX_SIZE = 100;//定义栈最大值常量

typedef void llist_op(struct Box recode);

template <class DataType>
class Stack
{
private:
	struct Box* data;
	int size;
	int top;

public:
	Stack();
	Stack(int s);
	~Stack();
	void push(DataType ch);
	DataType pop();
	DataType getTop();
	bool isEmpty();
	bool isFull();
	void setNull();
	void travel(llist_op op);
	class Full {};
	class Empty {};			//由于这两个类都是放在Stack这个类声明的里面, 所以我们将其称为异常内部类
};

typedef Stack<struct Box> BoxStack;

#endif // !_STACK_H_

stack.cpp

#include "stack.h"

template <class DataType>
Stack<DataType>::Stack()
{
	size = MAX_SIZE;
	top = -1;
	data = new DataType[MAX_SIZE];//缺省构造函数分配最大内存空间
}

template <class DataType>
Stack<DataType>::Stack(int s)
{
	size = s;
	top = -1;
	data = new DataType[size];//根据指定的大小分配栈的内存空间
}

//析构函数
template <class DataType>
Stack<DataType>::~Stack()
{
	delete[]data;//内存回收
}

template <class DataType>
void Stack<DataType>::push(DataType ch)
{
	//当堆栈是满时,丢出异常对象
	if (isFull())
		throw Full();
	data[++top] = ch;
}

template <class DataType>
DataType Stack<DataType>::getTop()			//成员函数:获得栈顶元素(不出栈)
{
	//当堆栈是空时,丢出异常对象
	if (isEmpty())
		throw Empty();
	return data[top];
}

template <class DataType>
bool Stack<DataType>::isEmpty()
{
	if (top == -1)
		return true;
	else
		return false;
}

template <class DataType>
bool Stack<DataType>::isFull()
{
	if (top+1 == size)
		return true;
	else
		return false;
}

template <class DataType>
DataType Stack<DataType>::pop()		//成员函数:出栈
{
	if (isEmpty())
		throw Empty();
	return data[top--]; //先出栈,top再自减
}

template <class DataType>
void Stack<DataType>::setNull()
{
	top = -1;
}

template <class DataType>
void Stack<DataType>::travel(llist_op op)
{
	if (isEmpty())
		throw Empty();

	for (int i = 0; i <= top; i++)
	{
		op( data[i]);
	}
}

template class Stack<Box>;

maze.h

#ifndef _MAZE_H_
#define _MAZE_H_

#include "stack.h"

//方向试探表示
typedef struct
{
	//x,y方向的增量
	int incX, incY;

}Direction;

//起点和终点坐标
typedef struct Setting
{
	int start_x, start_y;	//起点坐标:(start_x, start_y)
	int end_x, end_y;		//终点坐标:(endx, endy)
}Setting;

//栈中数据元素的组织
//栈中元素是一个由行、列、方向组成的三元组
typedef struct Box {
	int x;
	int y;	 //当前访问的迷宫格子的x,y坐标
	int di;  //当前方向
}Box;

#endif // !_MAZE_H_

maze.cpp

#include <iostream>
#include <iomanip>

#include "maze.h"
#include "stack.h"

using namespace std;

int maze[101][101];//0表示空地,1表示障碍物

bool findPath(int map[101][101], Direction direct[], BoxStack &s, Setting set)
{
	Box temp;
	int x, y, di;	//迷宫格子当前处理单元的xy坐标和方向
	int line, col;	//迷宫数组下一个单元的行坐标和列坐标

	map[set.start_x][set.start_y] = -1;
	temp = { 1,1,-1 };
	s.push(temp);
	while (!s.isEmpty()) //栈不为空
	{
		temp = s.pop();
		x = temp.x; y = temp.y; di = temp.di + 1;
		while (di < 4) //方向未尝试完
		{
			line = x + direct[di].incX;
			col = y + direct[di].incY;
			if (map[line][col] == 0)
			{
				temp = { x,y,di };
				s.push(temp);
				x = line; y = col; map[line][col] = -1;
				if (x == set.end_x && y == set.end_y)
					return true;//迷宫有路
				else di = 0;
			}
			else
				di++;
		}
	}
	return false;//迷宫没有路
}

void creatMaze(int m, int n)
{
	int i, j = 0;
	for (i = 0; j <= n + 1; j++)
		maze[i][j] = 1; //0表示空地,1表示障碍物
	for(i = m+1,j=0; j <= n + 1; j++)
		maze[i][j] = 1; //0表示空地,1表示障碍物
	for(i=0,j = 0; i <= m ; i++)
		maze[i][j] = 1; //0表示空地,1表示障碍物
	for (i=0,j = n+1; i <= m; i++)
		maze[i][j] = 1; //0表示空地,1表示障碍物
}

void Print_Maze(int m, int n)
{
	cout << "迷宫生成如下:";

	for (int i = 0; i <= m + 1; i++)
	{
		cout << endl;
		for (int j = 0; j <= n + 1; j++)
			cout << setw(3)<<maze[i][j] ;
	}

	cout << endl;
}

//如果用户能给我提供这样一个数据,我就可以将它给输出出来.
void print_s(Box recode)
{
	cout << recode.x <<" "<<recode.y<<" "<<recode.di<< endl;
}

int main(void)
{
	int m, n;
	Direction direct[4];
	Setting set;
	BoxStack s;

	direct[0].incX = 0; direct[0].incY = 1;//右
	direct[1].incX = 1; direct[1].incY = 0;//下
	direct[2].incX = 0; direct[2].incY = -1;//左
	direct[3].incX = -1; direct[3].incY = 0;//上

	cout<<"请设置迷宫的行数和列数,最大行数和列数均为100,输入以空格分隔。"<<endl;

	while (1)
	{
		cin >> m >> n;
		if (m > 100 || n > 100)
			cout << "输入有误,请重新输入:" << endl;
		else
			break;
	}

	cout << "请输入" << m << "行" << n <<"列的迷宫,"<< "输入以空格分隔。"<<endl;

	for (int i = 1; i <= m; i++)
	{
		for (int j = 1; j <= n; j++)
			cin >> maze[i][j]; //0表示空地,1表示障碍物
	}

	creatMaze(m, n);
	
	Print_Maze(m, n);

	cout << "请输入起点坐标,起点坐标需为空地且在地图上,输入以空格分隔。" << endl;
	while (1)
	{
		cin >> set.start_x >> set.start_y;
		if (set.start_x > m || set.start_y > n||maze[set.start_x][set.start_y]==1)
			cout << "起点坐标设置有误,请重新输入:" << endl;
		else
			break;
	}

	cout << "请输入终点坐标,终点坐标不能与起点坐标相同、需为空地且在地图上,输入以空格分隔。" << endl;
	while (1)
	{
		cin >> set.end_x >> set.end_y;
		if (set.end_x > m || set.end_y > n || maze[set.end_x][set.end_y] == 1|| (set.end_x== set.start_x&& set.end_y == set.start_y))
			cout << "终点坐标设置有误,请重新输入:" << endl;
		else
			break;
	}

	if (findPath(maze, direct, s, set))
	{
		cout << "寻路成功" << endl;
		try
		{
			s.travel(print_s);
		}
		catch (Stack<struct Box>::Empty)
		{
			cout << "Stack Empty" << endl;
		}
	}
	else
		cout << "迷宫没有路" << endl;
	
	Print_Maze(m, n);

	system("pause");
	return 0;
}

在这里插入图片描述

  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,我可以为您讲解C语言使用深度优先搜索算法解决迷宫问题深度优先搜索算法是一种用于遍历或搜索树或图的算法,它从起点开始,尽可能深地搜索每个可能的路径,直到找到目标节点或无法继续搜索为止。 在解决迷宫问题时,我们可以将迷宫看作一个图,其中每个格子都是一个节点,相邻的格子之间有一条边。我们可以使用深度优先搜索算法从起点开始遍历图,直到找到终点为止。在搜索过程中,我们需要记录当前路径,并且每次遍历到一个节点时,都需要判断它是否是终点,如果是终点则搜索结束,否则继续向下搜索。 以下是C语言代码示例: ```c #include<stdio.h> #define ROW 5 #define COL 5 int maze[ROW][COL] = { {0, 0, 0, 0, 0}, {0, 1, 1, 0, 0}, {0, 1, 1, 0, 0}, {0, 0, 0, 1, 0}, {0, 0, 0, 1, 0} }; int visited[ROW][COL] = {0}; //记录节点是否被访问过 int dx[4] = {0, 0, 1, -1}; //定义四个方向的移动 int dy[4] = {1, -1, 0, 0}; void dfs(int x, int y){ if(x<0 || x>=ROW || y<0 || y>=COL) return; //越界返回 if(visited[x][y] || maze[x][y]) return; //已访问或者是墙返回 visited[x][y] = 1; //标记为已访问 if(x == ROW-1 && y == COL-1){ //到达终点 printf("Find the way!\n"); return; } for(int i=0; i<4; ++i){ //向四个方向进行搜索 int nx = x + dx[i]; int ny = y + dy[i]; dfs(nx, ny); } } int main(){ dfs(0, 0); //从起点开始搜索 return 0; } ``` 在上述代码中,我们使用深度优先搜索算法从起点开始遍历迷宫,并且使用visited数组记录节点是否被访问过。在搜索过程中,我们向四个方向进行搜索,直到找到终点或者无法继续搜索为止。如果找到了终点,则输出"Find the way!",搜索结束。 希望这个例子可以帮助您理解C语言使用深度优先搜索算法解决迷宫问题

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xuechanba

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

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

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

打赏作者

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

抵扣说明:

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

余额充值