搜索算法入门

算法引入 \color{red}\text{算法引入} 算法引入

小时候,我们会玩一种迷宫游戏。下面就是非常简单的一种:

迷宫

(本文仅该图来源于网络) \color{grey}\text{(本文仅该图来源于网络)} (本文仅该图来源于网络)

完成该迷宫可以有很多种方法:

  • 正向搜索

  • 逆向倒推

不管使用哪一种方法,如果遇到走不通的路,我们都会到上一步的位置,然后重新寻找。只要反复地使用这种方法,我们就能够走出迷宫。

OI \text{OI} OI中,我们会把迷宫进行抽象化,例如用#表示障碍,.表示可走的位置,当然这样的操作只能还原普通的矩形迷宫(当然奇形怪状的迷宫就不行了)。

例如这个迷宫(数字表示长与宽):

3 5
. . # . # 
. . . . . 
# . . # .

另外,给出迷宫随机生成代码

假如在这个迷宫中,只能上下左右地移动,那么我们可以通过 ( 1 , 1 ) → ( 2 , 1 ) → ( 2 , 2 ) → ( 2 , 3 ) → ( 2 , 4 ) → ( 2 , 5 ) → ( 3 , 5 ) (1,1)\to (2,1)\to (2,2)\to (2,3)\to (2,4)\to (2,5)\to (3,5) (1,1)(2,1)(2,2)(2,3)(2,4)(2,5)(3,5)的路径抵达终点。

我们可以把迷宫保存在一个二维字符数组 m a p s i , j maps_{i,j} mapsi,j中。对于这四个方向,横纵坐标会做相应的变化:

  • → ( − 1 , 0 ) \to (-1,0) (1,0)

  • → ( 1 , 0 ) \to (1,0) (1,0)

  • → ( 0 , − 1 ) \to (0,-1) (0,1)

  • → ( 0 , 1 ) \to (0,1) (0,1)

当然,有的题目还可以使用左上、左下、右上、右下,横纵坐标这时会这样变化:

  • 左上 → ( − 1 , − 1 ) \to (-1,-1) (1,1)

  • 左下 → ( 1 , − 1 ) \to (1,-1) (1,1)

  • 右上 → ( − 1 , 1 ) \to (-1,1) (1,1)

  • 右下 → ( 1 , 1 ) \to (1,1) (1,1)

为了方便表示,我们可以维护两个一维数组来保存这些横纵坐标的变化量,例如,如果只保存上下左右的话:

int dx[]={
   -1,1,0,0},dy[]={
   0,0,-1,1};

假如八个方向都保存,则有:

int dx[]={
   -1,1,0,0,-1,1,-1,1},dy[]={
   0,0,-1,1,-1,-1,1,1};

假设当前在地图中的位置为 ( x , y ) (x,y) (x,y),则我们可以进行一个循环,每一次在 ( x , y ) (x,y) (x,y)的基础上增加 ( d x i , d y i ) (dx_i,dy_i) (dxi,dyi),得到新的位置 ( n x , n y ) = ( x + d x i , y + d y i ) (nx,ny)=(x+dx_i,y+dy_i) (nx,ny)=(x+dxi,y+dyi)。当然,还得考虑边界问题和题目中的障碍等问题。

接下来就粗略地复习一下两种搜索:

深度优先搜索 \color{green}\text{深度优先搜索} 深度优先搜索

第一种搜索叫做深度优先搜索,简称深搜,英文缩写为 DFS \text{DFS} DFS DFS \text{DFS} DFS适用于找到第一个符合要求的答案 DFS \text{DFS} DFS被形象地称为不撞南墙不回头的一根筋。之前的地图问题就适合用该方法。

该方法的模板:

void dfs(参数表)
{
   
    if(到达终点状态)
    {
   
        输出或保存结果;
        退出该层循环或整个程序;
    }
    for(拓展方式)
    {
   
    	if(该步合法)
        {
   
            修改、计算、标记;
            dfs(新的参数表);
            回溯;(可选)
        }
    }
}

广度优先搜索 \color{green}\text{广度优先搜索} 广度优先搜索

有深度,就有广度。广度优先搜索简称广搜,英文缩写为 BFS \text{BFS} BFS BFS \text{BFS} BFS适用于寻找最优解,个人认为要比 DFS \text{DFS} DFS要好用一些,但是需要维护队列,而队列的维护可以有两种:

  • 数组维护

  • STL:queue \text{STL:queue} STL:queue 维护

队列用数组维护一般来说效率会高一些,但是要控制空间大小,不宜过小(否则会 RE \text{RE} RE),也不宜过大(否则会 MLE \text{MLE} MLE)。

而用 STL \text{STL} STL中的 queue \text{queue} queue的话,可以不考虑空间,但是时间会略慢一些(恐怕所有 STL \text{STL} STL均是如此)。

数组维护的模板:

队列类型 q;//一般来说队列用q表示
int front=1,rear=1;//先定义头指针和尾指针,一开始一般都为1
while(front<=rear)
{
   
    队列类型 qf=q[front];//为了方便,可以保存头指针的队列元素
    for(拓展方式)
    {
   
        if(该步合法)
        {
   
            修改、计算、标记;
            q[++rear]=...;//入队
            if(到达终点状态)
            {
   
                进行重赋值或直接输出并退出;
            }
        }
    }
    front++;//头指针右移
}

queue \text{queue} queue维护的模板:

queue<队列类型>q;
while(q.size())//只要队列中有元素就继续操作
{
   
    队列类型 qf=q.front();//q.front()为头指针元素
    q.pop();//直接弹出队头
    for(拓展方式)
    {
   
        if(该步合法)
        {
   
            修改、计算、标记;
            q.push(...);//入队
            if(到达终点状态)
            {
   
                进行重赋值或直接输出并退出;
            }
        }
    }
}

应用与练习 \color{red}\text{应用与练习} 应用与练习

配套题单

这一次我们将练习下列题目:

题目 难度 来源 算法
P1443 马的遍历 \text{P1443 马的遍历} P1443 马的遍历 普及/提高- \color{FFC116}\text{普及/提高-} 普及/提高- BFS \text{BFS} BFS
P1135 奇怪的电梯 \text{P1135 奇怪的电梯} P1135 奇怪的电梯 普及/提高- \color{FFC116}\text{普及/提高-} 普及/提高- BFS \text{BFS} BFS
P1019 单词接龙 \text{P1019 单词接龙} P1019 单词接龙 普及/提高- \color{FFC116}\text{普及/提高-} 普及/提高- NOIP2000 \texttt{NOIP2000} NOIP2000 DFS+字符串处理 \text{DFS+字符串处理} DFS+字符串处理
U119869 迷宫 \text{U119869 迷宫} U119869 迷宫
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值