利用DFS和BFS解决基本的迷宫问题
思路
首先做出一下规定:
地图用一个二维数组表示,0表示可以通过,1表示不能通过,2表示起点,3表示终点
如何遍历数组中的上下左右四个位置的数?
设置一个标准数组,{1,0},{-1,0},{0,1},{0,-1},设数组为a[n][m]
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
for(k=0;k<4;k++)
{
if (i + direction[k][0] < n && i + direction[k][0] >= 0 && j + direction[k][1] >= 0 && j + direction[k][1] < m)
{
//a[i + direction[k][0]][j + direction[k][1]] 对这个进行操作即可
}
}
}
}
首先地图中的一个结点最多有4个邻接结点,先用数组存储地图信息,后将信息进行转置,使得其用图来表达,注意地图中为障碍的结点,我将其规定为没有邻接结点
利用BFS遍历与DFS对图进行遍历即可,我在之前的文章已经写过了(文章链接:利用BFS和DFS实现对无向图的遍历(图的表达方式为邻接矩阵和邻接表)-CSDN博客)
在此我就只介绍如何保存路径的问题?
同:DFS和BFS我都采用了string这个类来存储,在函数中对string类如果有进行修改操作,记得参数写为引用!!!
异:
在DFS中,因为是一个递推的过程,顺序是顺着来的,直接存放就行,同时如何在string中加字符,我是将‘0’+对应的结点的序号转换为一个ASIIIC码对应的字符再进行存入,输出时输出该字符减去‘0’就行
在BFS中采用了递归的思路,函数的返回值为bool型,如果递归到了结果点,则返回true,其余的情况进行||操作,来获得是否已经访问到终点的信息。存储路径的方式与上相同。
补充:
其实并不一定要用string,我现在觉得采用stack(栈)或者队列(queue)会更加简单。(博主写完代码才想起来,感觉绕了一大个圈来存储信息,博主有待进步)
代码
#include<iostream>
#include<string>
#include<queue>
using namespace std;
typedef struct node
{
int name;
node* next;
}node;
typedef struct NODE
{
node* nodedata;
string path;
}NODE;
class Graph
{
private:
node* AdjacencyList;
int num;//表示结点的总个数
int begin;//迷宫的起点
int end;//迷宫的终点
public:
Graph();
void BFS();
void DFS();
bool DFS(string &s,node*NODE,bool*judge);
};
/*在构造函数中实现了迷宫地图的读取,和将迷宫地图转换为图的邻接表的存储方式*/
Graph::Graph()
{
int direction[4][2] = { {1,0} ,{-1,0},{0,-1},{0,1} };
int n, m, i, j, k = 0;
cout << "输入迷宫地图的宽度" << endl;
cin >> m;
cout << "输入迷宫地图的长度" << endl;
cin >> n;
this->num = n * m;
int** map = new int* [n];
for (i = 0; i < n; i++)
{
map[i] = new int[m];
}
cout << "地图的详细详细信息" << endl;
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
cin >> map[i][j];
}
}
AdjacencyList = new node[n * m];
for (i = 0; i < n * m; i++)
{
AdjacencyList[i].next = NULL;
}
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
AdjacencyList[i * m + j].name = i * m + j;
if (map[i][j] == 2)
{
begin = i * m + j;
}
else if (map[i][j] == 3)
{
end = i * m + j;
}
for (k = 0; k < 4; k++)
{
if (i + direction[k][0] < n && i + direction[k][0] >= 0 && j + direction[k][1] >= 0 && j + direction[k][1] < m&&map[i][j]!=1)
{
if (map[i + direction[k][0]][j + direction[k][1]] == 0||
map[i + direction[k][0]][j + direction[k][1]] == 2||
map[i + direction[k][0]][j + direction[k][1]] == 3)
{
node* p = new node;
p->name = m * (i + direction[k][0]) + j + direction[k][1];
p->next = AdjacencyList[i * m + j].next;
AdjacencyList[i * m + j].next = p;
}
}
}
}
}
delete[] map;
}
void Graph::BFS()
{
cout << "---BFS----" << endl;
bool* judge = new bool[num];
for (int i = 0; i < num; i++)
{
judge[i] = false;
}
queue<NODE*>s;
judge[begin] = true;
NODE* head = new NODE;
head->nodedata = &AdjacencyList[begin];
char add = AdjacencyList[begin].name + '0';
head->path += add;
s.push(head);
while (!s.empty())
{
NODE* P = s.front();
s.pop();
node* p = P->nodedata;
p = p->next;
while (p != NULL)
{
if (judge[p->name] != true)
{
judge[p->name] = true;
NODE* x;
x = new NODE;
x->nodedata = &AdjacencyList[p->name];
char m = p->name + '0';
x->path += P->path+m;
if (p->name == end)
{
int n = x->path.size(),i;
for (i = 0; i < n; i++)
{
cout << x->path[i] - '0';
if (i < n - 1)
{
cout << "->";
}
}
cout << endl;
return;
}
s.push(x);
}
p = p->next;
}
}
cout << "无法到达终点" << endl;
}
void Graph::DFS()
{
cout << "---DFS----" << endl;
string s;
bool* judge = new bool[num];
for (int i = 0; i < num; i++)
{
judge[i] = false;
}
judge[begin] = true;
bool flag = DFS(s,&AdjacencyList[begin],judge);
if (flag)
{
for (int i =s.size()-1; i >=0; i--)
{
cout << s[i] - '0';
if (i > 0)
{
cout << "->";
}
}
cout << endl;
}
else cout << "无法到达终点" << endl;
}
bool Graph::DFS(string &s,node*NODE,bool*judge)
{
if (NODE->name == end)
{
char x = NODE->name + '0';
s += x;
return true;
}
else
{
bool flag = false;
node* p = NODE;
while (p->next != NULL)
{
if (!judge[p->next->name])
{
judge[p->next->name] = true;
flag=DFS(s, &AdjacencyList[p->next->name], judge) || flag;
}
p = p->next;
}
if (flag)
{
char x = NODE->name + '0';
s += x;
return true;
}
else
{
return false;
}
}
}
int main()
{
Graph a;
a.DFS();
a.BFS();
return 0;
}
总结:
代码有待加强,合理运用了ASSIIC码,个人认为分情况使用栈或者队列来存储会更加简单,这里用string略显麻烦,大家可以自行修改。