看了好多博客,终于弄懂了。。。。
某位大神的代码,我给他几乎每一行都来个注释,方便以后看
广度优先搜索的优点是找出的第一条路径就是最短路径,所以经常用来搜索最短路径,思路和图的广度优先遍历一样,需要借助于队列。
具体步骤:
(1)从入口元素开始,判断它上下左右的邻边元素是否满足条件,如果满足条件就入队列;
(2)取队首元素并出队列。寻找其相邻未被访问的元素,将其如队列并标记元素的前驱节点为队首元素。
(3)重复步骤(2),直到队列为空(没有找到可行路径)或者找到了终点。最后从终点开始,根据节点的前驱节点找出一条最短的可行路径。
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
struct point
{
int x;
int y;
};
int **Maze; //Maze是一个指针,指向的数据是int 指针类型 全局变量
point **Pre; // Pre是一个指针,指向的数据是point 指针类型 保存任意点在路径中的前一步
point move_ori[4]={{-1,0},{0,-1},{0,1},{1,0}};//移动方向为 行数减1,列数减1,列数加1 行数加1,
void Create(int row,int column){
//创建迷宫,注意到用0表示可走,1表示墙,将整个输入的迷宫再用墙围着,处理的时候就不用特别注意边界问题
int i,j;
for( i=0;i<row+2;i++)
{
Maze[i][0]=1;
Maze[i][column+1] = 1;
}
for( j=0; j<column+2; j++)
{
Maze[0][j] = 1;
Maze[row+1][j] = 1;
}
//接收正常的迷宫
for( i=1;i<row+1;i++)
{
for( j=1;j<column+1;j++)
{
cin>>Maze[i][j];
}
}
}
bool MazePath(int row,int column,int x,int y) 判断是否有路径从入口到出口,保存该路径(队列)
{
if(x==row && y==column) //输入的点就是终点
{
return true;
}
//创建队列,从(x,y)点开始,判断它上下左右的邻边元素是否有一个满足条件,如果满足条件就入队列;
queue<point> q; //定义队列q;
point now; //当前点,传进来的x,y就是当前点的坐标
now.x=x;
now.y=y;
q.push(now); //初始的入点加入队列
Maze[now.x][now.y]=-1; //标记当前点已经访问过了
while(!q.empty()) //队列不为空就不会跳出循环
{
now=q.front();//访问队首元素
q.pop();//删除队首元素
cout<<"清除队列中的("<<now.x<<now.y<<") "<<endl;;
for(int i=0;i<4;i++)//四个方向 取值为0 ,1 ,2 之前取成 1,2 ,3,4了
{
//往该方向走后能到达终点,则跳出循环,且返回ture 跳出函数体
if(now.x+move_ori[i].x==row && now.y+move_ori[i].y==column)
{
Maze[now.x+move_ori[i].x][now.y+move_ori[i].y]=-1; //标记此点访问过了
Pre[row][column] = now; //标记到达Maze[now.x+move_ori[i].x][now.y+move_ori[i].y]这个点的前一个点, 但是 [row][column] 为什么是这个??
return true;
}
if(Maze[now.x+move_ori[i].x][now.y+move_ori[i].y]==0) //该方向不是墙,可以走通
{
//
point temp; //下个位置
temp.x=now.x+move_ori[i].x;
temp.y=now.y+move_ori[i].y; //对原来的坐标进行改变,
cout<<"move_ori[i].x="<<move_ori[i].x<<" move_ori[i].y="<<move_ori[i].y<<" "<<endl;
q.push(temp); //将新加入的点压入队列当中
Maze[temp.x][temp.y]=-1; //下一个位置标记为访问过 对其他点的下一步展示为墙
Pre[temp.x][temp.y]=now; // //保存任意点在路径中的前一步 保存走到当前点的前一点是什么, 用于之后输出路径。
cout<<"Pre["<<temp.x<<"]["<<temp.y<<"]=("<<now.x<<" "<<now.y<<") "<<endl;
}
}
}//结束while
return false;
}
//根据Pre输出最短路径
void PrintPath(int row,int column)
{
stack<point> s; //定义栈 用于保存路径。 先入后出
point temp;
temp.x=row;
temp.y=column;
while(temp.x!=1|| temp.y!=1)
{
s.push(temp);
temp=Pre[temp.x][temp.y];
}
//从栈中输出
cout<<"(0,0)"<<endl; //(0,0在上一步是没有入栈的,需手动输出)
while(!s.empty())
{
temp=s.top(); 访问栈顶
cout<<"("<<temp.x-1<<","<<temp.y-1<<")"<<endl;
s.pop(); //删除栈顶元素 及出栈。。。
}
cout<<endl;
}
int main()
{
int row,column;//迷宫的行数和列数
cin>>row>>column;
//初始化迷宫,cin
Maze = new int*[row + 2]; //分配一个元素个数为row+2的数组,数组的元素为int型指针 *是在int后面,
Pre= new point*[row+2];
for(int i=0; i<row+2; i++){
Maze[i] = new int[column + 2]; //为maze(i)申请 列那么多个int 在Maze的第i个元素分配column+2个int元素的空间。其后可以使用p[i][0]到p[i][column-1]个元素
Pre[i] = new point[column + 2]; //如果没有这个for循环的话,在Create迷宫的时候,会出错,相当于没有创建成功二维数组。
}
Create(row,column);
//寻找迷宫出口
if(MazePath(row,column,1,1))
PrintPath(row,column);
return 0;
}