算法之路——深搜、广搜(简单搜索)

搜索

通过一定的顺序,枚举每一个数据(经常会通过一些判断条件去掉无意义的数据,即剪枝),找到想要的数据的过程。

深度优先搜索(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 Cow
hdu1241 Oil Deposits
poj3414 Pots
poj4116:拯救行动
hdu 1180 诡异的楼梯
poj2488:A Knight’s Journey

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值