初学搜索算法

搜索分为DFS 深度优先搜索 和 BFS 广度优先搜索。搜索的大致结构都为一棵树的形状。

1.  首先我们先来说一下DFS,DFS为深度优先搜索,他的最大特点就是深度优先,以深度为准则,一路走下去,直到达到目标。如果没有达到目标而且又无路可走, 就会返回上一步(这就是所说的回溯)。从他使用的数据结构来看,他所用的是栈, 先进后出。

   我以一道排列数字的题目为例子进行讲解。

 

 这里以n = 3 为例子进行解释。首先第一个位置可以先把数字1填上去1_ _,

然后接着进行下一步,数字1已经填写过那么下一步可以把2填写上去,现在的结果是1 2 _ ;

接着再往下继续走,1,2都已经填写过了,只剩下数字3,所以他的结果只能是1 2 3;

此时,3位数字已经全部填写完成,这一种方案已经实现,那么它就可以返回上一步再次进行下一种方案。此时数字排列情况为1 2 _,只剩下3可以进行填写zong jie,但是由于1 2 3这种排列方式已经有了,所以说不符合要求,继续返回上一步,这种状态下的排列情况是1 _ _, 2已经填写过了,所以可以把数字3填写上去,排列情况是1 3 _,;

再往下继续排列,是剩下数字3,此时再次完成一种排列方式1 3 2;

3 个数字再次填写完成之后,再次返回上一步,1 3_, 数字2 已经写过,所以继续返回上一步 1 _ _, 第二个位置可以选择的数字只有2 ,3,这两个数字都已经填写完毕,再次返回上一步_ _ _,

首位是1的方案已经全部找到,接下来可以接着从 2 开始,方法与上述相同。

把我所写代码贴在这里,供大家参考:

​
#include<iostream>

using namespace std;

const int N = 10;

int path[N];//保存序列
int state[N];//数字是否被用过
int n;

void dfs(int u)
{
    if(u > n)//数字填完了,输出
    {
        for(int i = 1; i <= n; i++)//输出方案
            cout << path[i] << " ";
        cout << endl;
    }

    for(int i = 1; i <= n; i++)//空位上可以选择的数字为:1 - n
    {
        if(!state[i])//如果数字 i 没有被用过
        {
            path[u] = i;//放入空位
            state[i] = 1;//数字被用,修改状态
            dfs(u + 1);//填下一个位
            state[i] = 0;//回溯,取出 i
        }
    }
}

int main()
{

    cin >> n;
    dfs(1);
    return 0;
}

​

2.     接着来说一下 BFS ,BFS与DFS不同的是,DFS在搜索过程中不管有多少岔路口都是一路走下去,直到找到目标或者是无路可走再返回上一个路口,而 BFS 则是在面对岔路口时,先把所有的岔路口都记录下来,然后选择其中一个进入,然后将它的分路情况记录下来,然后再返回来进入另外一个岔路,并重复这样的操作。从他使用的数据结构来看, 他所用的数据结构是队列 (queue), 先进先出。

   我依然以一道走迷宫的题为例子进行讲解:

 从最开始(1,1)位置开始,查看上下左右四个方向是否有路可走,如果可以,则标记为1,以上图为例,标记为1的只有一种情况,那么就接着往下走,走到 1 的位置上时,继续查看上下左右是否有路可走,如果可以则标记为 2, 此时只有一条路,那么就沿着这条路往下走走到 2 的位置,在 2 的位置查看,发现有向下和向右两条路可以走,那就把这两条路全部标记为 3 ,任意选择一条路走下去,把它能走的路标记完之后,再次走到另外一个 3 的路上把它能走的路也全部标记,接着任选一条标记为 3 的路接着走下去,后面就像上述所,描述的一样,直到走到终点。此时走到终点的路就是最短路。

把我所写代码粘贴上去供大家参考:

​
#include <cstring>
#include <iostream>
#include <queue>

using namespace std;

typedef pair<int, int> PII;

const int N = 110;

int g[N][N];//存储地图
int f[N][N];//存储距离
int n, m;

void bfs(int a, int b)//广度优先遍历
{
    queue<PII> q;
    q.push({a, b});//存下初始点位置
    f[0][0] = 0;
    while(!q.empty())
    {
        PII start = q.front();
        q.pop();
        g[start.first][start.second] = 1;
        int dx[4] = {0, 1, 0, -1}, dy[4] = {-1, 0, 1, 0};
        for(int i = 0; i < 4; i++)//往四个方向走
        {
            int x = start.first + dx[i], y = start.second + dy[i];//当前点能走到的点
           
            if(g[x][y] == 0) //如果还没有走过
            {
                g[x][y] = 1;//走到这个点,并计算距离
                f[x][y] = f[start.first][start.second] + 1;//从当前点走过去,则距离等于当前点的距离+1.
                q.push({x, y});//这个点放入队列,用来走到和它相邻的点。
            }

        }
    }
    cout << f[n][m];
}

int main()
{
    memset(g, 1, sizeof(g));
    cin >> n >>m;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> g[i][j];
        }
    }
    bfs(1,1);
    return 0;
}

​

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值