广度优先搜索--POJ迷宫问题
Description
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
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) 分析:这道题很明显是一道寻找最短路径的问题,那就应该选择广度优先搜索,首先来说说广搜吧,广搜的基本思想是这样的:
从初始状态S开始,利用规则,生成所有可能的状态。构成树的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则。生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。
也就是如下图所示:
我们来看一下维基上的代码:
std::queue<node*> visited, unvisited;
node nodes[];
node* current; unvisited.push(&nodes[]); //先把root放入unvisited queue while(!unvisited.empty()) //只有unvisited不空
{
current = (unvisited.front()); //目前應該檢驗的 if(current -> left != NULL)
unvisited.push(current -> left); //把左邊放入queue中 if(current -> right != NULL) //右边压入。因为QUEUE是一个先进先出的结构,所以即使后面再压其他东西,依然会先访问这个。
unvisited.push(current -> right); visited.push(current); cout << current -> self << endl; unvisited.pop();
}
首先是有一棵构建好的树,我们从跟节点开始,访问第一层子节点,然后是第二层...这些都应该不难理解。问题是,我们应该怎么初始化这样一棵树,然后怎么记录路径,因为一般给的都只是一个序列,首先你要根据这个序列初始化一棵树然后才能在这棵树的基础上去找。
这里就只考虑迷宫问题吧,首先题目给的是一个二维序列,那么我们就可以直接将这个二维序列看成一棵树,节点就是迷宫路上的每一个格子(非墙),走迷宫的时候,格子间的关系是什么呢?按照题目意思,我们只能横竖走,因此我们可以这样看,格子与它横竖方向上的格子是有连通关系的,只要这个格子跟另一个格子是连通的,那么两个格子节点间就有一条边。如果说本题再修改成斜方向也可以走的话,那么就是格子跟周围8个格子都可以连通,于是一个节点就会有8条边(除了边界的节点)。
下面是记录路径的问题,对于记录路径,我们可以采用回溯法,在每个node里面设一个变量记录它前面的元素,那么在遇到正确结果后就可以以该元素为根往回遍历直到最开始的元素,在每个节点处打印,那这样就把整条路径打印出来了。如:
struct node{
int pre;
int x;
int y;
} path[]; void print(int i) {//当前节点
if (path[i].pre != -) {//找到前面那个节点
print(path[i].pre);
cout << "(" << path[i].x << "," << path[i].y << ")" << endl;
} else {//最前面的那个节点
cout << "(" << path[i].x << "," << path[i].y << ")" << endl;
}
}
另外一个方法是采用一个stack来专门记录路径,下面我用一个流程来说明:
--》--》...--》--》
--》--》--》...--》--》...--》--》...--》--》
从流程中我们可以看出来了,就不多说了。。。
第三种方法是在node里面设一个list专门记录路径,但是这个方法要记得在每次走到下一个节点的时候将它的父节点的路径记录加上自己的坐标变成自己的路径记录,就像下面这样:
struct node {
list<int*> path;
int x, y;
node(list<int*> fatherList) {
path = fatherList;
int index[] = {x, y};
path.push_back(index);
}
};
那么在找到最后一个的路径的时候就可以直接打印它的path变量。
有人也许会有疑问,为什么广搜找到的路径就是最短了呢?,看看下面这个图你就明白了:
--》
发现数字的规律了吗?数字是分层的,在同一层的数字所代表的路径长度是相同的,一层层的遍历,当某层第一次到达了出口,这层肯定是最短路径所在层啦。
下面是那道题的代码:
#include <iostream> using namespace std; int map[][]; //相邻四个节点
int borderUponX[] = {, , , -};
int borderUponY[] = {, -, , }; int front = , rear = ; struct node{
int pre;
int x;
int y;
} path[]; void print(int i) {//当前节点
if (path[i].pre != -) {//找到前面那个节点
print(path[i].pre);
cout << "(" << path[i].x << "," << path[i].y << ")" << endl;
} else {//最前面的那个节点
cout << "(" << path[i].x << "," << path[i].y << ")" << endl;
}
} void bfsSearch(int x, int y) {
//开始节点(出发),前面没有节点了
path[front].x = x;
path[front].y = y;
path[front].pre = -; //当front == rear的时候说明已经走完了所以“相邻”节点
//且都不通
while (front < rear) {
for (int i = ; i != ; i++) {
//相邻节点坐标
int pathX = path[front].x + borderUponX[i];
int pathY = path[front].y + borderUponY[i]; //不符合的节点(遇到边界或已经走过了)
if (pathY < || pathX < || pathX > || pathY > || map[pathX][pathY])
continue;
else {//将front的相邻的可以过去的并且是还没有走过的节点加到路径里面
map[pathX][pathY] = ;
path[rear].x = pathX;
path[rear].y = pathY;
path[rear].pre = front;
rear++;
}
if (pathX == && pathY == ) {
//找到了一条路径,又是第一次找到
//那么就是最短路径了
print(rear - );
break;
}
}
front++;
}
} int main(int argc, char const *argv[])
{
for(int i = ;i < ;i++)
for(int j = ;j < ;j++)
cin >> map[i][j]; bfsSearch(,);
return ;
}
广度优先搜索--POJ迷宫问题的更多相关文章
- POJ 2251 Dungeon Master /UVA 532 Dungeon Master / ZOJ 1940 Dungeon Master(广度优先搜索)
POJ 2251 Dungeon Master /UVA 532 Dungeon Master / ZOJ 1940 Dungeon Master(广度优先搜索) Description You ar ...
- 深度优先搜索(DFS)和广度优先搜索(BFS)求解迷宫问题
用下面这个简单的迷宫图作为例子: OXXXXXXX OOOOOXXX XOXXOOOX XOXXOXXO XOXXXXXX XOXXOOOX XOOOOXOO XXXXXXXO O为通路,X为障碍物. ...
- AOJ 0558 广度优先搜索
题意:在 H * W 的地图里有 N 个工厂,每个工厂分别生产硬度为1-N 的奶酪,有一只老鼠准备把所有奶酪都吃完.老鼠的初始体力值为1,每吃一个奶酪体力值加 1.已知老鼠不能吃硬度大于当前体力值的奶 ...
- 广度优先搜索(BFS)----------------(TjuOj1140_Dungeon Master)
这次整理了一下广度优先搜索的框架,以后可以拿来直接用了.TjuOj1140是一个三维的迷宫题,在BFS时我增加了一个控制数组,用来对队列的出队进行控制,确保每次出队的结点均为同一步长的结点,个人认为比 ...
- 步步为营(十六)搜索(二)BFS 广度优先搜索
上一篇讲了DFS,那么与之相应的就是BFS.也就是 宽度优先遍历,又称广度优先搜索算法. 首先,让我们回顾一下什么是"深度": 更学术点的说法,能够看做"单位距离下,离起 ...
- BFS(三):双向广度优先搜索
所谓双向广度搜索指的是搜索沿两个方向同时进行:(1)正向搜索:从初始结点向目标结点方向搜索:(2)逆向搜索:从目标结点向初始结点方向搜索:当两个方向的搜索生成同一子结点时终止此搜索过程. 广度双向搜索 ...
- 广度优先搜索(Breadth First Search, BFS)
广度优先搜索(Breadth First Search, BFS) BFS算法实现的一般思路为: // BFS void BFS(int s){ queue<int> q; // 定义一个 ...
- 关于宽搜BFS广度优先搜索的那点事
以前一直知道深搜是一个递归栈,广搜是队列,FIFO先进先出LILO后进后出啥的.DFS是以深度作为第一关键词,即当碰到岔道口时总是先选择其中的一条岔路前进,而不管其他岔路,直到碰到死胡同时才返回岔道口 ...
- 算法竞赛——BFS广度优先搜索
BFS 广度优先搜索:一层一层的搜索(类似于树的层次遍历) BFS基本框架 基本步骤: 初始状态(起点)加到队列里 while(队列不为空) 队头弹出 扩展队头元素(邻接节点入队) 最后队为空,结束 ...
随机推荐
- [AHOI2009]最小割 最小割可行边&必须边
~~~题面~~~ 题解: 做这题的时候才知道有最小割可行边和必须边这种东西..... 1,最小割可行边, 意思就是最小割中可能出现的边. 充要条件: 1,满流 2,在残余网络中找不到x ---> ...
- POJ2987:Firing——题解
http://poj.org/problem?id=2987 题目大意: 炒掉一个人能够获得b收益(b可以<0),但是炒掉一个人必须得炒掉他的下属(然后继续递归). 求最大收益和此时最小裁员. ...
- JavaScript中的函数与栈
Javascript中会经常用到setTimeout来推迟一个函数的执行,如: setTimeout(function(){ alert("Hello World"); },100 ...
- Codeforces Round #532 (Div. 2):F. Ivan and Burgers(贪心+异或基)
F. Ivan and Burgers 题目链接:https://codeforces.com/contest/1100/problem/F 题意: 给出n个数,然后有多个询问,每次回答询问所给出的区 ...
- POJ1679:The Unique MST(最小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 38430 Accepted: 14045 ...
- [nginx]proxy_pass&rewrite知识点
While passing request nginx replaces URI part which corresponds to location with one indicated in pr ...
- 题解【luogu4168 [Violet]蒲公英】
Description 给出一个长度为 \(n\) 序列 \(a\) ,\(m\) 次询问,每次询问区间 \([l,r]\) 里的众数(出现次数最多的数).若有多个,输出最小的. \(a_i \leq ...
- bzoj 4414 数量积 结论题
数量积 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 389 Solved: 147[Submit][Status][Discuss] Descri ...
- bzoj 2599 [IOI2011]Race 点分
[IOI2011]Race Time Limit: 70 Sec Memory Limit: 128 MBSubmit: 4768 Solved: 1393[Submit][Status][Dis ...
- HDU3585 最大团+二分
maximum shortest distance Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...