迷路アルゴリズム(DFS)

1.スタックが迷路検出に使用される場合、それは深さ優先探索(DFS)と呼ばれ、基本的に再帰的検出のアイデアと同じであり、再帰的方法の非再帰的バージョンと見なすことができます。

2.迷路検出にキューを使用するのは、幅優先探索(BFS)です。幅優先探索方法は、キューの特性を利用し、レイヤーごとに展開して、歩きやすい正方形を見つけます。出口が見つかるまで、見つかった答えが見つかります。最初はそれが最短でなければなりません。

例えを使用すると、DFSは、ロボットが迷路を歩く方法をシミュレートするのに適しています。一方向が開いていることを確認すると、ロボットは永遠に進み、行き止まりに遭遇すると戻ります。BFSは、の入り口で一人で立っているようなものです。迷路とたくさんの小さな検出器を取り出します。各小さな検出器は、見つけることができるパスを検索するのに役立ちます。出口を最初に見つけた人はフィードバックを送信し、この人はこの小さな検出器が見つけたパスをたどって迷路を歩きます。 。

迷路の問題

ここに画像の説明を挿入します

迷路問題のデータ構造

ここに画像の説明を挿入します

方向テスト:迷路を歩くシーケンスを記録するために使用されます:右下と左上

注:ここで迷路を歩くには、右下と左上の原則に従います
ここに画像の説明を挿入します
ここに画像の説明を挿入します

スタック内のデータ要素の編成:現在の位置と方向を保存してから、Box構造をスタックにプッシュするために使用されます

Box構造体のdiの値は1〜3で、これはdircet構造体配列の最初の要素を表し、直接構造体配列の各要素は移動方向を表します。
ここに画像の説明を挿入します

特定のポイントまで繰り返さないようにする

ここに画像の説明を挿入します

あなたがたどる道はスタックにプッシュされます

行き止まりに遭遇すると、ロールバックが実行されます。各ロールバック中に、進む方法があるかどうかがチェックされます。後退のプロセス中に、間違ったパスがスタックからポップされ、正しいパスが表示されます。スタックに残ります。

スタック情報を逆の順序で出力して、正しいパスを出力します

ここに画像の説明を挿入します

ここに画像の説明を挿入します

ここに画像の説明を挿入します

メモリループは、現在位置が右下、左上、4方向に移動できるかどうかを判断するのと同じです。可能であれば、一時的に保存されている現在位置要素をスタックにプッシュしてから、現在位置を移動位置に更新します。 、次にメモリループに入り、上下左右に移動できるかどうかを判断します。

注:tempは、ループの内側のループが終了した後、毎回現在の位置ポイントの前のポイントを保存する必要があります。

内側のループの終わりの条件:1。迷路から抜け出します2.行き止まりに遭遇します

アウターループ機能:1。初めてアウターループに入ると、現在の位置座標がtempによって保存された位置に更新され、次に方向が順番に移動するため、temp.di +1に更新されます。右下と左上である必要があります。したがって、+ 1の後にdi = 0の場合、方向は右に移動します。

2.メモリループが行き止まりに遭遇すると、内側のループを出て外側のループに入ります。このとき、外側のループがスタックから飛び出し、スタックの一番上の要素と上の要素が飛び出します。ポップされるスタックの一番上が内側のループです。位置が上下左右に移動できないことがわかりました。

以下は、スタックの最上位を外側のループにポップした後の操作手順です。

tempによって予約された要素のポイントは、現在の位置の前のポイントであることに注意してください。

ここに画像の説明を挿入します
main.cpp

#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
#include"stack.hpp"
#define M 4
#define N 4
//迷宫   maze[M+2][N+2]
int maze[M + 2][N + 2] =
{
    
    
	{
    
    1, 1, 1, 1, 1, 1},
	{
    
     1,0,0,1,1,1 },
	{
    
     1,0,0,0,0,1 },
	{
    
     1,0,1,1,1,1 },
	{
    
     1,0,0,0,0,1 },
	{
    
     1,1,1,1,1,1 },
};

//用来记录走迷宫顺序的结构体
typedef struct {
    
    
	//int cx,int cy表示x和y方向的增量
	//cy+1:表示向右走  cy-1:向左走
	//cx+1:表示向下走  cx-1:向上走
	int cx, cy;
}Direction;
//数组中方向村粗顺序:右下左上
Direction direct[4] = {
    
     {
    
    0,1},{
    
    1,0},{
    
    0,-1},{
    
    -1,0} };

//用来记录当前位置,然后压入栈中
typedef struct {
    
    
	int x, y;//记录当前位置的坐标
	int di;//记录当前位置下一次移动的方向
}Box;

//判断是否走出迷宫的代码
//参数1:迷宫图 参数2:存放方向的数组 参数3:保存通路的栈
bool findPath(int maze[M + 2][N + 2], Direction direct[], LinkStack<Box>& s)
{
    
    
	//创建Box temp结构体来保存当前位置
	Box temp;
	//记录当前位置和方向
	int x=0, y=0, di=0;
	//记录下次移动的位置坐标
	int line=0, col=0;
	//一开始点位于迷宫maze[1][1]的位置,所以将该位置的值变为-1
	maze[1][1] = -1;
	//temp值记录当前位置,将di设置为-1
	temp = {
    
     1,1,-1 };
	//将temp记录的当前位置压入栈中
	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].cx;
			col = y+direct[di].cy;
			//判断下一个位置能否走
			if (maze[line][col] == 0)
			{
    
    
				//如果下一个位置能够移动,就更新temp存储当前位置的值
				temp = {
    
     x,y,di };
				//将temp结构体存储当前位置的信息压入栈中
				s.push(temp);
				//更新当前位置
				x = line;
				y = col;
				//当前位置的值改为-1,表示走过了,下次不能走
				maze[line][col] = -1;
				//判断当前位置是否为迷宫出口
				if (x == M && y == N)
				{
    
    
					//把迷宫出口也压入栈中
					temp = {
    
     x, y, di };
					s.push(temp);
					//找到出口,退出函数
					return true;
				}
				else {
    
    
					//没有找到出口,但是可以移动到下一个点,那么下一个点起始移动方向更新为右,因为移动方向顺序:右下左上
					di = 0;
				}
			}
			else 
			{
    
    
				//比如一开始要往右走:如果右方向不能走,就要改变方向移动
				di++;
			}
		}

	}
	return false;
}
//测试打印迷宫通路
void test()
{
    
    
	LinkStack<Box> s;
	findPath(maze, direct, s);
	//逆序遍历栈
	int i = 0;
	int num = s.size();
	Box* data = new Box[num];
	while (!s.isEmpty())
	{
    
    
		//头删
		data[i++] = s.getTop();
		s.pop();
	}
	//对数组进行逆序遍历
	for(int j = num-1; j >=0; j--)
	{
    
    
		cout << "(" << data[j].x << "," << data[j].y << ")" << endl;
     }

}
int main()
{
    
    
	test();
	system("pause");
	return 0;
}

stack.hpp

#include<iostream>
#include<string>
#include<cstdlib>
using namespace std;
//节点结构体
template<class Data>
struct node {
    
    
	Data data;
	node<Data>* next;
};
//链表类
template<class Data>
class LinkStack 
{
    
    
private:
	node<Data>* top;
	int num;
public:
	//不需要有参构造函数
	LinkStack();
	~LinkStack();
	void push(Data val);
	Data pop();
	Data getTop();
	bool isEmpty();
	int size();
	class Empty{
    
    };
};
template<class Data>
LinkStack<Data>::LinkStack()
{
    
    
	//这里用的是无头链表
	num = 0;
	top = NULL;
};
template<class Data>
void LinkStack<Data> :: push(Data val)
{
    
    
	//在堆区开辟一块空间,来存放第一个节点
	node<Data>* newNode = new node<Data>;
	newNode->data = val;
	//无头链表的头插法
	newNode->next = top;
	//链表指向第一个节点
	top = newNode;
	num++;
}
template<class Data>
Data LinkStack<Data>::pop()
{
    
    
	//如果链表为空,就抛出异常
	if (top == NULL)
	{
    
    
		throw Empty();
	}
	//不为空,进行头删的操作
	//先释放再头删
	//注意要保存住被删除1的节点
	node<Data>* temp = top;
	Data tempData = top->data;
	//注意:要先把top移到下一个节点,再进行释放操作
	top = top->next;
	delete temp;
	num--;
	return  tempData;
}
template<class Data>
Data LinkStack<Data>::getTop()
{
    
    
	return top->data;
}
template<class Data>
bool LinkStack<Data>::isEmpty()
{
    
    
	if (top == NULL)
		return true;
	return false;
}
template<class Data>
LinkStack<Data>::~LinkStack()
{
    
    
	while (top)
	{
    
    
		node<Data>* temp = top;
		top = top->next;
		free(temp);
     }
	node<Data>* top = NULL;
}
template<class Data>
int LinkStack<Data>::size()
{
    
    
	//计算链表的长度
	return num;
}

試験結果:
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/m0_53157173/article/details/114486303