搜索(DFS和BFS)

搜索是一种非常实用的算法,分为DFS(深度优先搜索)和BFS(广度优先搜索)

DFS(深度优先搜索)

我们先不讲图的DFS,我们先讲一个小例子。(参考《啊哈算法》)
假设我们手上有标号为1~n的n张牌,我们面前有n个盒子,那么我想知道将每一张牌放入盒子中有多少种方法。
先从简单的三张牌开始。

  • 我们先站在1号盒子面前,此时我们手中有标号为1,2,3的牌,我们可以随机放一张,这里为了便于之后讲解,先放一张1,往后移动。
  • 之后我们站在了二号盒子面前,此时我们手中有2,3.这里我们放2,往后移动。
  • 最后我们站在了三号盒子面前,我们手中只有3了,那么我们放3。
  • 此时我们手上已经没有牌了,那么我们的放牌的方法的数目ans便加一,并且我们拿回3这张牌,并且回退到上一步,拿掉牌2。此时我们站在盒子2面前,手中有2,3。
  • 这一次我们选择放3,之后再在3号盒子放2。ans加一。
    看懂了这里之后我们便大致知道了DFS的操作过程是什么了。
  1. 首先我们要分析我们每一步能干什么,比如我们这里便是可以每一步放什么牌,而有些逃脱类的搜索题型,我们便分析我们在当前位置,我们能如何走。
  2. 我们要找到一种可解决问题的路径,或者无法解决问题。那么我们要么答案加一之后回溯,要么直接回溯到上一步。如果上一步还不行,那么我们继续回溯。这很明显是一个递归的过程。值得提及的是,我们一般会设置一个标记数组,用来标记当前位置是否已经放过了,避免产生重复。
  3. 最后统计结果。
void dfs()
{
	if()判断是否需要回溯的条件。
	{
		return;
	}
	for()
	{
		循环当前位置所能做的操作。
		if()判断是否越界或者条件不满足或者障碍物等情况。
			continue;
		if()满足条件的话
		{
			mark[][]=1;先将标记数组标记。
			dfs();在递归下一步。
			mark[][]=0;将标记取回。
		}
	}
	return;
	这个return十分关键,因为他代表着当前此种路径失败,不能走这条路,我们要换一条。
}

这是一套我总结出来的dfs模板,其中主要有几点值得注意。

  1. 我们需要抽象出每一步要做什么,以及抽象出回溯的条件。
  2. 我们要在一次失败的dfs或者某种已经成功的路径返回的时候将mark数组的标记取回。
  3. dfs我们求得的并非唯一解,他可以求出很多的解,其中最优解不能单纯靠上面的模板找出。

BFS(广度优先搜索)

BFS相较于DFS有一个优势,他的答案会是最优解,所以他的运行时间理论上会短于DFS。
那么BFS的思路是啥呢。记得我们的DFS他就相当于一条路走到黑,你不见南墙不回头。而BFS呢,他有一点是和DFS一样的,也就是搜索的共性,我们要抽象出在当前位置,我们能干什么。DFS是能走就走,莽就是了;而BFS就很有意思了,他是将当前位置所有能走的所有情况全部存入一个队列当中。

没找到啥好题,先将就着:POJ - 2251
这是一个三维的BFS题型,相较于二维的题型,其实很简单,就相当于多了些当前位置能进行的操作。

2020.2.27号添加说明
先将就这个题看。
**题意:**你困在一个三维的地方,你要逃出去。
**分析:**这是一道很简单的搜索题目,我们分析一下。首先,在每一个位置,我们每一步可以上下左右前后,那么我们就将上下左右前后中的位置并且满足条件的(即不是障碍物的地方)放入队列,步数你可以用结构体存,也可以开个数组,然后把当前位置出队。当队列的队首已经是E的位置的时候,我们就直接输出步数就OK了。

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int i,j,k;
int l,r,c;
char mm[31][31][31];
int mark[31][31][31];
int headi,headj,headk,taili,tailj,tailk;
struct weizhi
{
    int x,y,z;
    int time;
};
queue<weizhi>q;
void bfs(int x,int y,int z)
{
    struct weizhi t;
    mark[x][y][z]=1;
    int nowx=x,nowy=y,nowz=z;
    int nextx,nexty,nextz;
    t.time=0;
    t.x=x;
    t.y=y;
    t.z=z;
    q.push(t);
    while(!q.empty())
    {
        struct weizhi tt;
        tt=q.front();
        q.pop();
        for(i=0; i<6; i++)
        {
            //遍历无法逃出
            //6种情况,上下左右前后
            if(i==0)
            {
                t.x=tt.x;
                t.y=tt.y;
                t.z=tt.z+1;
                t.time=tt.time+1;
            }
            else if(i==1)
            {
                t.x=tt.x;
                t.y=tt.y;
                t.z=tt.z-1;
                t.time=tt.time+1;
            }
            else if(i==2)
            {
                t.x=tt.x+1;
                t.y=tt.y;
                t.z=tt.z;
            }
            else if(i==3)
            {
                t.x=tt.x-1;
                t.y=tt.y;
                t.z=tt.z;
                t.time=tt.time+1;
            }
            else if(i==4)
            {
                t.x=tt.x;
                t.y=tt.y+1;
                t.z=tt.z;
                t.time=tt.time+1;
            }
            else
            {
                t.x=tt.x;
                t.y=tt.y-1;
                t.z=tt.z;
                t.time=tt.time+1;
            }
            if(t.x<0||t.x>l||t.y<0||t.y>r||t.z<0||t.z>c)
                continue;
            //此为遇到障碍物不入队列
            if(mm[t.x][t.y][t.z]=='#')
                continue;
            //此为可通点入队列
            if(mark[t.x][t.y][t.z]==0&&(mm[t.x][t.y][t.z]=='.')||mm[t.x][t.y][t.z]=='E')
            {
                //printf("x:%d\ty:%d\tz:%d\ttime:%d\n",t.x,t.y,t.z,t.time);
                mark[t.x][t.y][t.z]=1;
                q.push(t);
                if(mm[t.x][t.y][t.z]=='E')
                {
                    printf("Escaped in %d minute(s).\n",t.time);
                    return ;
                }
            }
        }
    }
    printf("Trapped!\n");
    return;
}
int main()
{
    while(~scanf("%d %d %d",&l,&r,&c))
    {
        if(l==0&&r==0&&c==0)
            break;
        getchar();
        memset(mark,0,sizeof(mark));

        for(i=0; i<l; i++)
        {
            for(j=0; j<r; j++)
            {
                for(k=0; k<c; k++)
                {
                    scanf("%c",&mm[i][j][k]);
                    if(mm[i][j][k]=='S')
                    {
                        headi=i;
                        headj=j;
                        headk=k;
                    }
                    if(mm[i][j][k]=='E')
                    {
                        taili=i;
                        tailj=j;
                        tailk=k;
                    }
                }
                getchar();
            }
            if(i!=l-1)
                getchar();
        }
        /*if(bfs(headi,headj,headk)!=-1)
            printf("%d\n",bfs(headi,headj,headk));
        else
            printf("Trapped!\n");*/
        bfs(headi,headj,headk);
        while(!q.empty())
        {
            q.pop();
        }
    }
}

2020.2.24暂未总结出BFS模板以及未找到合适题型,留待日后修改。

总结

其实搜索总而言之是一种,特殊的暴力,因为他也是相当于有遍历所有情况的思想,但是他是一种优雅的暴力,在算法中,算很简单的算法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值