广度优先搜索--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(队列不为空) 队头弹出 扩展队头元素(邻接节点入队) 最后队为空,结束 ...
随机推荐
- Python logging(日志)模块
python日志模块 内容简介 1.日志相关概念 2.logging模块简介 3.logging模块函数使用 4.logging模块日志流处理流程 5.logging模块组件使用 6.logging配 ...
- [洛谷P5174]圆点
题目大意:给你$R(R\leqslant10^{14})$,求:$$\sum\limits_{x\in\mathbb{Z}}\sum\limits_{y\in\mathbb{Z}}[x^2+y^2\l ...
- BZOJ3542 DZY Loves March 【map + 线段树】
题目链接 BZOJ3542 题解 线段树裸题,,对每一行每一列开线段树 由于坐标很大,用\(map\)维护根下标 化一下式子,只用维护区间和,区间平方和,区间存在的个数 #include<alg ...
- AOJ.863 分书问题 (DFS)
题意分析 现有n个人,n种书,给出每人对n种书的喜欢列表,求有多少种方案满足以下条件: 1.每个人都分得自己喜欢的书: 2.每个人分得书的种类各不相同,即所有种类的书均得到分配 1.采用生成测试法 生 ...
- 多线程中Local Store Slot(本地存储槽)[转]
1. 使用ThreadStatic特性 ThreadStatic特性是最简单的TLS使用,且只支持静态字段,只需要在字段上标记这个特性就可以了: [ThreadStatic] static str ...
- ACE线程管理机制-并发控制
ACE有若干可用于并发控制的类.这些类可划分为以下范畴: ACE Lock类属 ACE Guard类属 ACE Condition类属 ACE Synchronization类 由于篇幅较长,我分别写 ...
- BZOJ:2460[BeiJing2011]元素 (异或基+贪心)
2460: [BeiJing2011]元素 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2910 Solved: 1535 题目链接:https: ...
- Javascript利用递归实现数组的快速排序
// 定义快速排序方法 function quickSort(arr){ // 设置递归的终止条件 if( arr.length <= 1){ return arr; } // 获得数组arr的 ...
- ES6 利用集合Set解决数组 交集 并集 差集的问题
根据阮一峰老师的ES6教程自己体会而写的,希望能给一些朋友有帮助到 let a = new Set([1,2,3,4]) let b = new Set([2,3,4,5,]) 并集 let unio ...
- 【C++ STL】容器概要
1.容器的共通能力 1. 所有的容器都是“value”语意,而不是“reference”语意.容器进行元素的安插操作时,内部实施的都是拷贝操作,置于容器内.因此STL容器的每个元素都必须能被拷贝.如 ...