基本搜索算法(DFS|BFS)

本文介绍了基本的图算法——深度优先搜索(DFS)和广度优先搜索(BFS)。DFS如同走迷宫,选择一条路走到底,遇到障碍回溯;BFS则按层次进行搜索。文章通过5x5迷宫和勘探石油问题阐述了DFS的应用,并以芒果销售商搜索解释了BFS的概念,同时给出了两个BFS的应用实例:寻找最短路径问题和可乐平分问题。
摘要由CSDN通过智能技术生成

基本搜索算法(DFS|BFS)

这周的题目中设计到的算法:DFSBFS 都是基本的图算法,图是一种数据结构,可以表示出节点之间的关系。

基本搜索算法有两种策略:

  • 深度优先
  • 广度优先

[1] 深度优先搜索

我们对一个图进行搜索,无非就是寻找某种状态,深度优先顾名思义,就是寻找某种状态的时候选择一条路走到底,走不通就退回去换另一条路。

就像走迷宫那样,我们把迷宫抽象为一个图,路就是图里面的边,路两端的地方抽象为节点。走出这个迷宫就可以看作是我们要寻找的一个状态,在不清楚迷宫构造和不破换游戏规则的情况下,找到出口只能一个一个去尝试,为了不出现在同一条路上绕来绕去的尴尬情况,我们需要标记过我们到过的地方,然后一直往深处走,走到头若发现此路不通或已经走过,那自然就要原路返回到前一个岔路口去走另一条路。这种方法虽然比较笨比较低效,但只要迷宫有出口就一定可以出的去。

有了这个例子,很容易归纳出深度优先的基本方法:

  1. 选择一个初始节点
  2. 从这个初始节点开始寻找,标记走过的节点
  3. 如果走到不能再走,回到前一个可以走另一条路的状态(回溯)
  4. 找到目标状态、退出

因为我们很难判断要走多少层,再由第3步很容易联想到递归。

那么找到目标状态和走到不能再走就是递归的结束条件。

DFS 理解起来到是不难,关键在于对实际问题的抽象,下面是几道关于DFS的题

  1. 5×5迷宫

定义一个二维数组:

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

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output

左上角到右下角的最短路径,格式如样例所示。

这道题和之前举得例子相似,只是多了两个条件:1.路要最短 2.要记录走过的路径

那就需要走过所有的路,记录每条路所走过的路径。

代码如下:

#include <stdio.h>
#include <string.h>
#define MAXN 5

int vst[MAXN][MAXN];     // 访问标记,记录是否走过
int map[MAXN][MAXN];     // 坐标范围
int depth = 0;           // 路长
int mindh = MAXN * MAXN;
int path[MAXN * MAXN][MAXN * MAXN];
int min, count = 0;
int dir[4][2] = 
{
    {
  0, 1}, {
  0, -1}, {
  1, 0}, {-1, 0}   
};

int CheckEdge(int x, int y)            // 边界、约束判断      
{
    // 如果节点没走过且没有越界
    if ((x >= 0 && x < MAXN && y >= 0 && y < MAXN) && !map[x][y] && !vst[x][y])
        return 1;
    return 0;
}

void dfs(int x, int y)
{
    path[count][depth] = x*10 + y;
    depth++;
    vst[x][y] = 1;  // 标记访问过的节点

    if (x == MAXN - 1 && y == MAXN - 1)
    {
        if (depth < mindh)
        {                         
            mindh = depth;  // 更新最短路径
            min = count;    // 记录存储最短路径节点的下标
            count++;
            memcpy(path[count], path[count-1], sizeof(path[count-1]));                      
        }
        return;
    }
    // 往其他的方向尝试
    for (int i = 0; i < 4; i++)
    {
        if (CheckEdge(x + dir[i][0], y + dir[i][1]))
        {
            dfs(x + dir[i][0], y + dir[i][1]);
            vst[x + dir[i][0]][y + dir[i][1]] = 0;
            depth--;                    // 走另一条路
        }
    }
    return;
}

<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值