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

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

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

迷宫示例图像如下:
迷宫问题 -- 深度优先搜索算法DFS_第1张图片
程序实现使用了递归思想,没有用到堆栈知识。
迷宫问题 -- 深度优先搜索算法DFS_第2张图片
实现的代码:

#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;
}

测试数据如下:逗号为英文字符,可以在记事本中一起直接复制粘贴。
迷宫问题 -- 深度优先搜索算法DFS_第3张图片
迷宫问题 -- 深度优先搜索算法DFS_第4张图片
上述代码还有优化的地方。
迷宫问题 -- 深度优先搜索算法DFS_第5张图片

//定义方向数组
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.
迷宫问题 -- 深度优先搜索算法DFS_第6张图片
迷宫问题 -- 深度优先搜索算法DFS_第7张图片
迷宫问题 -- 深度优先搜索算法DFS_第8张图片
M+2和N+2表示的是围墙的两行和两列。
迷宫问题 -- 深度优先搜索算法DFS_第9张图片
迷宫问题 -- 深度优先搜索算法DFS_第10张图片
迷宫问题 -- 深度优先搜索算法DFS_第11张图片
这里走的迷宫遵循的都是顺时针原则:即 右-下-左-上 的原则。
迷宫问题 -- 深度优先搜索算法DFS_第12张图片
最原汁原味版的迷宫程序
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;
}

迷宫问题 -- 深度优先搜索算法DFS_第13张图片

你可能感兴趣的:(算法,javascript)