搜索
通过一定的顺序,枚举每一个数据(经常会通过一些判断条件去掉无意义的数据,即剪枝),找到想要的数据的过程。
深度优先搜索(dfs)
深度优先搜索属于图算法的一种,是一个针对图和树的算法,应为缩写为dfs(Depth First Search)。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便解决很多相关的图论问题,如最短路径问题等等。一般运用堆数据结构来辅助实现DFS算法。——百度百科
上面是百度百科关于深度优先搜索的描述。其实,简单来说,就是“不撞南墙不回头”——按照一定的规则,先找一个方向上的数据,如果找到头还没找到想要的,那就找另一个方向上的数据。
迷宫
以迷宫为例:
如图,左上角是起点,右下角是终点。如果给我们做,我们可以一眼看出答案,但是电脑却很难“看”出来,因为电脑一次只能看一个格。所以就需要一个一个格子去看是否能走,一直找到中间点。
如果我们规定只能走上下左右,并且按照深搜的规定,每次选择按照“上下左右”的顺序走,这样在起点就有下和右两个方向可以走,先选择向下走:
走完后,有上、下、右三个方向可以走,但是上已经走过了,所以还是只有下、右可以走,继续向下走………………
已经没有路可以走了,这时就要进行回溯,即往回走,一直回溯到上一次有两条路可以选择的时候
也就是这个时候,继续按照之前的方法走,遇到路口按照“上、下、左、右”的顺序选择方向、遇到死路就回溯,这样可以一直找到终点。
伪代码
dfs是以递归为基础的
void dfs(){
//递归出口
if(结束条件){
return ;
}
//递归主体
for(……){
if(下一步有效){
book[] = 1;//标记已经走过的路
dfs();//进行下一步
book[] = 0;//回溯的时候一定要记住消除影响
}
}
}
广度优先搜索(BFS)
广度优先搜索是连通图的一种遍历算法,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和广度优先搜索类似的思想,属于一种盲目搜寻法,目的是系统的展开并检查途中的所有节点,以找寻结果。换句话说,他并不考虑结果的可能位置,彻底的搜过整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有算法均被访问,则算法终止。一般用队列数据结构来辅助实现BFS算法。
与深度优先搜索的不撞南墙不回头不同,广度优先搜索更像是步步为营,每次把所有能走的点都存在队列中,然后一一拿出来,看看拿出来的点所能走到的点,把能走到的点再存进队列,这样在迷宫中”铺“出路来。
迷宫
还是那个迷宫
首先,起点能走的点有右和下,存进队列
从队列中取出点,寻找下一层能走的点。
依次往下找,直到找到终点。
伪代码
q.push(起点);//将起点推入队列
while(!q.empty()){//当队列不为空,即:没有搜完所有点时
temp = q.front();//取出队列第一个点
q.pop();//将队列第一个点推出队列
if(temp是终点) break;
for(……){
q.push(下一步能走的点);//把下一步能走的点推入队列
book[] = 1;//标记
}
}
例题
- 描述:一个迷宫有R行C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到),只能在水平方向或垂直方向走,不能斜着走。
- 输入:第一行是两个整数,R和C,代表迷宫的长和宽。(1<=R,C<=40)接下来是R行,每行C个字符,代表整个迷宫。空地格子有“.”表示,有障碍物的格子用“#”表示。迷宫左上角和右下角都是“.”。
- 输出:输出从左上角走到右下角至少要经过多少步(即至少需要经过多少个空地格子)。计算步数要包括起点和终点。
代码
#include<bits/stdc++.h>
using namespace std;
//方向数组
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
//图的长宽
int l,w;
//存图的字符串数组
char _map[50][50];
//步数
int step = 1;
int minn = 2500;
//bfs用到的结构体,表示一个坐标
struct node{
int x;
int y;
int def;//第几步
node(int xx,int yy){x = xx;y = yy;}
};
//深搜
void dfs(int x,int y){
if(x == l - 1&&y == w - 1){
minn = min(minn,step);
}
for(int i = 0;i < 4;i++){
int tx = x + xx[i];
int ty = y + yy[i];
if(tx >= 0&&ty >= 0&&tx < l&&ty < w&&_map[tx][ty] == '.'){
step++;
_map[tx][ty] = '#';
dfs(tx,ty);
_map[tx][ty] = '.';
step--;
}
}
}
//广搜
void bfs(){
queue<node> q;
while(!q.empty()) q.pop();
node temp(0,0);
temp.def = step++;
q.push(temp);
while(!q.empty()){
temp = q.front();
q.pop();
if(temp.x == l - 1&&temp.y == w - 1){
printf("%d\n",temp.def);
return;
}
for(int i = 0;i < 4;i++){
node tt(temp.x + xx[i],temp.y + yy[i]);
tt.def = temp.def + 1;
if(tt.x >= 0&&tt.y >= 0&&tt.x < l&&tt.y < w&&_map[tt.x][tt.y] == '.'){
_map[tt.x][tt.y] = '#';
q.push(tt);
}
}
}
}
int main()
{
//读入地图
scanf("%d%d",&l,&w);
for(int i = 0;i < l;i++)
scanf("%s",_map[i]);
//深搜
/*
dfs(0,0);
printf("%d\n",minn);
*/
//广搜
step = 1;
bfs();
return 0;
}
/*
5 5
..###
#....
#.#.#
#.#.#
#.#..
*/
题目
poj3984 迷宫问题poj3278 Catch That Cowhdu1241 Oil Depositspoj3414 Potspoj4116:拯救行动hdu 1180 诡异的楼梯poj2488:A Knight’s Journey