一些BFS参考的博客:
https://blog.csdn.net/ldx19980108/article/details/78641127
https://blog.csdn.net/u011437229/article/details/53188837
https://blog.csdn.net/m0_37316917/article/details/70879977
关于queue头文件常用函数的解释:
https://www.cnblogs.com/xuning/p/3321733.html
具体内容等做到了慢慢写,现在还在研究queue
迷宫问题
定义一个二维数组:
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0
Sample Output
(0, 0) (1, 0) (2, 0) (2, 1) (2, 2) (2, 3) (2, 4) (3, 4) (4, 4)
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <stack> #include <queue> using namespace std; /*做这题有了很多新感悟,如果是要探求一共有几种解法的话,那么我应该使用DFS算法, 但要是求最短路径的话,BFS算法是按层算的,所以它能更容易算出最短路径*/ /*这道题有个令人舒服的操作就是讲队尾的数据不断抽出(因为有个指针不断指向父节点) 然后放入堆栈中,再一个个从堆栈顶部抽出,所以我最后得出的数据要是最后的指针*/ int map[6][6], newx[4]={-1,1,0,0}, newy[4]={0,0,-1,1}; bool sign[6][6]; class location { public: int x,y;//坐标 location* father;//指向父节点的位置 }; location* bfs() { int x, y; queue<location*> Q;//建立关于location指针的队列 location* begin = new location();//【重要】这里需要new一个空间来放置新数据 begin->x = 1; begin->y = 1; begin->father = NULL; //初始化起点,其父节点为空,要放在函数内创建队列【重要】 Q.push(begin);//放入队列的第一个点 while ( !Q.empty() )//这里是队列和堆栈常用的判断方式,若为空队列则返回1 { location* linshi = Q.front(); Q.pop();//获得第一个地址后就可以将它从队列里拉出来了 for ( int i=0 ; i<4 ; i++ )//开始了哦,四方遍历 { x = linshi->x + newx[i]; y = linshi->y + newy[i]; if ( x<1 || x>5 || y<1 || y>5 ) continue; //超出边界,判断下一个点吧 if ( sign[x][y] == true ) continue; //如果这个点已经走过了,我也不会再回头 if ( map[x][y] == 1 ) continue; //如果有墙壁的话,我当然不会傻傻撞上去的啦 //经过上面的三连判断,终于,这个点是可以走过去的 location* NEW = new location(); NEW->x = x; NEW->y = y; NEW->father = linshi; //建立一个新指针,将这个可行点代入数值 if ( x==5 && y==5 ) return NEW; //已经达到终点了哦,把这个地址带回去吧 Q.push(NEW);//不满足上面这个条件呀,那就将这个点放入队列之中吧 sign[x][y] = true;//本点到此一游,来过了哦 } } } int main() { for(int i=1;i<=5;i++) { for(int j=1;j<=5;j++) { cin>>map[i][j];//初始化迷宫 sign[i][j]=false;//重置sign数组 } } location* p=bfs();//将最后得到的地址赋给p stack<location*> S; while ( p != NULL )//只要指针不为空的话 { S.push(p); p = p->father; } while( !S.empty() )//只要堆栈不为空的话 { location* temp = S.top();//依旧是新建一个指针,其等于堆顶的地址 S.pop();//【得到它的信息便可以删除啦】 cout<< "(" << temp->x-1 << ", " << temp->y-1 << ")" <<endl; } return 0; }
这些代码的灵感很多来自于下面的代码,【】中做的是我的注释
#include<iostream> #include<queue> #include<stack> using namespace std; int migong[5][5];//保存迷宫图 bool flag[5][5];//标记改点是否到达过 class Stat { public: int x,y; int t; Stat* father;//指向其父状态,用于逆向寻找路径 }; int R[4][2]={ -1,0, 1,0, 0,-1, 0,1 };//用于状态扩展 Stat* BFS()//返回终点状态 { queue<Stat*> Q;//用于存储还没有被扩展的(即将扩展)状态//【指向这个位置】 int x=0,y=0,t=0; Stat* start = new Stat();//这里是我栽过大坑,由于是在函数内部定义的对象,必须要用new来分配内存与堆中 start->x=start->y=0;//【start的位置为(0,0)】 start->t = 0; start->father = NULL;//开始状态没有父状态 //【上面这几句话是初始点的初始化】 Q.push(start);//【这里是放入第一个点的意思】 while( Q.empty() == false )//直到搜索完所有状态退出循环 { Stat* temp = Q.front();//【新建一个临时的指针指向队头】 Q.pop();//【删除队头,虽然是删除队头,但是这个指针本身并未消失,只是被移出】 for(int i=0;i<4;i++)//这里就是状态的扩展,向上下左右四个方向扩展 { x = temp->x + R[i][0]; y = temp->y + R[i][1]; if(x<0||y<0||x>4||y>4)//超出边界,便直接舍弃该状态 continue; if(flag[x][y] == true)//到达过该状态,也直接舍弃 continue; if(migong[x][y] == 1)//没有路,也直接舍弃 continue; //【上面这三连判断的代码很酷,很对我口味】 Stat* tempS = new Stat();//创建新状态 tempS->x = x; tempS->y = y; tempS->t = temp->t+1;//时间加一 tempS->father = temp;//指向父节点 //【上面这段作用主要是将可行点放入队列中】 if( x == 4 && y == 4 ) { return tempS;//搜索到了终点,便返回 } Q.push(tempS);//将新状态加入队列中 flag[x][y] = true;//标记该状态已经到达过 } //【这段for循环后,刚开始进入的点的所有可能性都放入队列中,准备进入下一 //个阶段,继续检索这个队列】 } return start; } int main() { for(int i=0;i<5;i++)//循环输入迷宫 { for(int j=0;j<5;j++) { cin>>migong[i][j]; flag[i][j] = false;//全部重置为未标记 } } Stat* p = BFS(); stack<Stat*> S;//声明堆栈S //放入栈中,主要是为了让其反序,不然从目标状态找其父节点遍历的话,是反的 //【这个想法很好,不这么做的话从队列里先出来的是终点】 while(p != NULL)// { S.push(p); p = p->father; } while(S.empty() == false) { Stat* temp = S.top(); S.pop();//【得到它的信息便可以删除啦】 cout<< "(" << temp->x << "," << temp->y << ")" <<endl; } }