关于深度优先搜索一些小小看法,也是结合了一些大佬的代码

蒟蒻来谈谈深度优先搜索。

关于深度优先搜索,首先需要确定这道题是不是可以搜出答案,一直往下搜索,如果可以出答案,那就说明深搜是可以的。

首先,如果我们需要输出搜素中我们的选择,这时候我们可能需要传入一个表示当前走到哪里的参数,第二个,如果我们需要计算出和最大或者是最小问题,我们可能传入一个参数,用来表示他们的和,第三个参数,也就是我们经常说的步数,我们可能要记录我们走了多少步,所以我们往往需要一个step的参数,来表示我们走了多少步,又或者,我们需要选完这个数后,我们要选比这个数大的数,我们此时也需要记录我们当前的数。

初步谈完了关于参数的传入,我们来谈谈关于终止条件,为什么要有终止条件呢,这是很重要的,不然我们的搜索不会停止,无法得到我们需要的结构,搜说条件往往是我们已经遇到死胡同了,接下来没有路可以走了,或者是说,我们已经收集好我们要的东西了,我们不需要再进行搜素了,这些都是需要我们进行终止的,而往往伴随着终止的是一个更新,我们需要更新我们最大值啊1,或是更新我们的最小值啊,又或者进行输出啊,当然是满足我们终止的条件下进行的啦,然后别忘了,我们在终止完后要return哦,不然你搜完第一次就卡在那里了,哪里能达到我们搜索的目的呢,你说是吧。

再来谈谈我们搜说的核心部分,首先我们要试探一下,试探这个点的下一个点有没有被搜索过,也就是说我们在前面要有一个东西,也就是一个判断的数组,来表示我们的下一个东西有没有被搜索过,如果有,可以continue,如果没有,那就标记下一个点为被搜索的状态,并进行递归调用我们的dfs,传入我们的下一个搜索点,注意参数往往要改变,也许是步数的加一,也许是和的加,也可以是下一个点的值,都要结合题目要求具体分析,然后也是比较重要的一点,我们需要进行清理现场,就是说我们要把我们前面标记的拿掉,让他可选择,这样我们就完成了整个dfs的搜索过程。

第一次写这个写的并不好,我们还是来看题吧。

第一题,n皇后问题

P1219 [USACO1.5] 八皇后 Checker Challenge

#include<iostream>头文件

using namespace std;变量空间

主函数方面,我们正常输入,然后开搜就行。

题目是要我们输出列数,那我们按行进行搜索,那么参数自然也变成了行,一方面我们确认了行肯定不会重复,接下来我们只需要关心列数和对角线即可,同时我们也确定了终止条件,见下。

由于题目要求输出前三个解,我们需要一个total变量来记录我们收集了多少个解答,如果total小于2证明我们的解答需要进行输出,至于终止条件呢,就是我们已经搜索到最后一行了。

这里我们要输出答案,所以需要一个数组,来存储我们的答案。每次输出完就total加一就好了,别忘了return .

接下来,进入搜索好戏,按照我们前面说的,我们需要判断能不能进行搜索,自然是判断其这一列和这一对角线和另一对角线能不能走,如果能走,请标记一下,然后肆无忌惮的走下去,接下来恢复现场标记为0,哦耶,一道搜索题就被解决了。

于是乎,八皇后也不过尔尔,不过是从行开始搜素,判断一下列,对角线有没有被访问过,没有就搜索,然后判断终止条件,就是我们答案到底有几次,三次就不输出了,然后每次total加一下就可以了。
int a[100], b[100], c[100], d[100];

int total;
int n;
void queen(int i)
{
    if (i > n)
    {
        if (total <= 2)
        {
            for (int k = 1; k <= n; k++)
                cout << a[k] << " ";
            cout << "\n";
        }
        total++;
        return;
    }
    else
    {
        for (int j = 1; j <= n; j++)
        {
            if ((!b[j]) && (!c[i + j]) && (!d[i - j + n]))
            {
                a[i] = j;
                b[j] = 1;
                c[i + j] = 1;
                d[i - j + n] = 1;
               
                queen(i + 1);
                b[j] = 0;
              c[i + j] = 0;
           d[i - j + n] = 0;
              
            }
        }
    }
}
int main()
{
    cin >> n;
    queen(1);
    cout << total;
   return 0;
}

好咧,我们来看第二道,

P1036 [NOIP2002 普及组] 选数

我们依然来理清一下思路,首先我们有一堆数字,我们要从中选择,每个数可以选可以不选,我们不断进行选择,到3个数字后就进行回溯,并且记录次数就可以。

其实到这里我们其实提前确定了终止条件,就是我们的步数达到了k,我们顺带判断一下素数函数,如果可以我们就可以直接让答案ans++就好了,对了,我自己都差点忘了,我们要return!!!!

由于我们要计算和,那我们也需要一个用来计算和的参数,也就是sum,到这里我们就确认了两个参数,不过我们以后要从当前选的这个数后面的数字进行选择,所以我们还需要一个starx进一步选择,到这里我们已经确认了所有参数,最后一个可能会难以理解一点,不过没关系哈,我们可以代码见,由于这道题并没有什么需要进行标记,我们这里其实已经愉快的结束了,在下次搜索的时候只需要将m++,再将starx++就可以了,然后加上return 进行恢复现场就好了。

#include<iostream>
#include<algorithm>
#include<string>
#include<math.h>

头文件


using namespace std;

变量空间
int n,  k;

输入的数字和要选的数字
int a[100000];


long long ans = 0;
bool isprime(int a) {
    if (a == 1)
    {
        return 0;
    }
    for (int i = 2; i * i <= a; i++)
    {
        if (a % i == 0)
            return false;
    }
    return true;
}

一个判断素数的函数
void dfs(int m,int sum,int starx)
{
    if (m==k)
    {
        if (isprime(sum))
        {
            ans++;
        }
        return;
    }

    for (int i = starx; i < n; i++)
    {
        dfs(m + 1, sum + a[i], i + 1);

    }
    return;


}


int main()
{

    cin >> n;
    cin >> k;
    for (int i = 0; i <n ; i++)
    {
        cin >> a[i];
    }

输入工作


    dfs(0, 0, 0);
    cout << ans;

    return 0;
}

气氛都烘托到这里了,那就再来一道。

P1605 迷宫

这道题是标准的dfs好吧。

首先进行起点和终点的输入,至于终止条件,我们很容易就可以想到,就是我们到终止条件了,那我们的ans++,最后输出就好。

关于输入方面的我就不再进行赘述。

我们有一个迷宫对吧,我们得确定迷宫有没有被走过,不妨一开始假设所有迷宫格子都没有被走过,我们全部初始化为1,当然为0其实也不错,看个人习惯哈。

然后我们输入障碍物,因为障碍物不能走,我们将所在格子弄成0.这样我们就完成了预处理工作,

然后我们要dfs,我们直接从起点开始搜索就好,这道题也不需要步数,也不是总和,那我们就传入两个坐标就好。

在起点搜索之前,我们要先将起点弄成不能走,也就是0.这样才代表我们的起点已经被我们走过了。

好嘞,真正开搜,我们要搜素起点的上下左右,那我们自然可以一个个试试,但有更好的做法,弄两个偏移量数组,一个是x轴方向的偏移量,y轴方向同理,那我们就定义两个一维数组,然后传入4个x和y坐标即可,然后我们需要一层For循环,用来搜素这四个点,如果可以走,那么请在走之前,赋值为0,代表已经走过了,然后大胆走下去,由于我们改变了标记量,那我们就让他返回现场,再赋值为0就好。

于是一道搜素题就这样结束了。

是不是不是很难?

#include<iostream>


using namespace std;
int maze[100][100] ={0};
int n, m, t, sx, sy, fx, fy, ans = 0;
int dx[4] = { -1,1,0,0 };
int dy[4] = { 0,0,-1,1 };
void dfs(int x, int y)
{


    if (x == fx && y == fy)
    {
        ans++;
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        if (maze[x + dx[i]][y + dy[i]] == 1)
        {
            maze[x + dx[i]][y + dy[i]] = 0;
            dfs(x + dx[i], y + dy[i]);
            maze[x + dx[i]][y + dy[i]] = 1;
        }


    }

}

int main()
{
    int x, y;

    cin >> n >> m >> t;
    cin >> sx >> sy >> fx >> fy;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            maze[i][j] = 1;地图的初始化,全部都能走
        }


    }
    for (int i = 0; i < t; i++)
    {
        cin >> x >> y;
        maze[x][y] = 0;障碍物的初始化,不能走

    }

    maze[sx][sy] = 0;起点标记为不能走。

    dfs(sx, sy);


    cout << ans;

    return 0;好习惯,继续保持

}

今天就到这里了,感谢诸君与各位道友,人生何处不相逢,期待下次再见!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值