假期学习dfs(深搜)

深度优先搜索的关键在于当下如何做,然后采用递归的方法,进行下一步的搜索,直到到达边界或者是其他的条件限制.
这里用一个简单的搜索案例引入:

要求输入一个数,然后输出1~n的全排列:

试想一下假如有3个数字即(n==3),

  1. 首先对于第一个位置,我们可以放1或2或3。 如果为1,然后手里剩余2和3,然后继续在第二个位置。

  2. 既可以放2,又可以放3,那么第二个位置,1就不可以再放了, 所以我们需要一个标记数组来记录该数字用没用,所以需要一个book数组。

  3. 然后第一个位置放完之后,我们需要在第二个位置放数字,由于这和第一次放数字是一个道理,所以这里用到了递归。不过位置变为了第二个位置,那么我们第二次调用的时候,就要去做一个判断,哪个数字用过了,就把它用对应的book数组标记为1,否则,才放数字。

  4. 一轮递归完成后,就说明第一次牌全部放完了,那么对应的牌应该收回,所以调用递归的后面应该将book数组变为0。

  5. 说到递归,那么首先要想到的应该是递归的结束条件,本题的结束条件应该为所走的位置比实际的大,即递归结束。

void dfs(int step)
{
    int i;
    if(step==n+1)
    {
        for(i=1;i<=n;i++)
        {
            printf("%d",a[i]);
        }
        printf("\n");

        return ;        //返回之前的一步(最近一次调用dfs函数的地方)

    }
    //在第step个盒子里面该放哪张牌?
    //依次尝试
    for(i=1;i<=n;i++)
    {
        if(book[i]==0)
        {
            a[step]=i;
            //第i张牌已经放进第step个盒子里面了
            book[i]=1;
            //牌已经放进盒子里面了,不再手中了
            dfs(step+1);
            book[i]=0;
            //因为有循环操作,所以要将牌收回;
        }
    }
    return ;
}                                                                            

以上就是代码部分,一定要注意递归结束的时候会有一个return,这个return会将函数退回到上一个递归调用的地方。
由以上可知,我们的dfs代码的基本步骤如下

void dfs(int step)
{
	判断边界
	尝试每一种可能 for(i=1;i<=n;i++)
	{
		继续下一步 dfs(step+1)
	}
	返回
}

我们趁热打铁,继续来看一看一个救人问题,当初看到很多方格里面要找一个人的坐标问题,当时感觉这个很奇妙,今天终于也有空闲时间学习这个了。
刚刚我们已经了解了深搜的代码部分,它最重要的就是要找到递归的边界以及当下如何做,然后以后的每一步和当下一样。

我们先来看看题目

小哈从起点开始,越过障碍物,到达终点,需要的最小步数,走一小格算一步

在这里插入图片描述

  1. 既然要在方格里走,那么每在一个地方,他就有最多4个方向可走,最少两个方向可走。
    于是就要每次尝试一种走法,那么我们就需要一个方向数组next数组。

  2. 那么我们总不能把走过来又走回去吧,于是和上一道题目一样,我们需要一个book数组,这次我们需要记录的为走过的地点的坐标。

  3. 我们在地图中要做到怎样的判断才能够继续走下一步,首先我们需要考虑,所走的点有没有越界(即在地图外),其次我们还需要判断点的坐标是否已经走过了,以及是否为障碍物。

  4. 接下来需要想一想结束的条件,无非就是小哈所在点的坐标和终点坐标一样时,递归结束。

  5. 由于每次进行一次递归时,就会有一个总步数,我们只需将里面最小的值保留下来就行。

void dfs(int x,int y,int step)
{
    int next[4][2] = {{0,1}//向右走
                     ,{1,0}//向下走
                     ,{0,-1}//向左走
                     ,{-1,0}};//向上走
    int tx,ty,k;
    //判断是否为小哈的位置
    if(x==p && y==q)
    {
        if(step<min)
        {
            //更新步数的最小值
            min=step;
        }
        return;    //一定不能忘记
    }
    //
    for(k=0;k<=3;k++)
    {
        //计算下一个点的坐标
        tx=x+next[k][0];
        ty=y+next[k][1];
        //判断是否越界
        if(tx<1 || tx>n || ty<1 || ty>m)
            continue;
        //判断该店是不是障碍物和该点是否已经走过
        if(a[tx][ty]!=1 && book[tx][ty]!=1)
        {
            book[tx][ty]=1;    //尝试该点
            dfs(tx,ty,step+2);
            book[tx][ty]=0;    //尝试结束,收回该点
        }
    }
    return ;
}                                                                

							注意迷宫里面的x和y是这样子定义的

在这里插入图片描述

发布了6 篇原创文章 · 获赞 5 · 访问量 96

猜你喜欢

转载自blog.csdn.net/weixin_45870050/article/details/104071882