前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DFS-深度优先搜索(Depth First Search)—1

DFS-深度优先搜索(Depth First Search)—1

作者头像
指点
发布2019-01-18 17:33:58
4840
发布2019-01-18 17:33:58
举报
文章被收录于专栏:指点的专栏指点的专栏

深度优先搜索算法,作为最常用的算法之一,在很多地方都有它的身影,也被很多人称为“万能的搜索”,可能这个说话有点过了,但是由此也可以看出它有多么强大。好了,多说无益,我们一起来看看这个“万能的算法”的真面目:

代码语言:javascript
复制
先从一道题目说起:假设现在有0~9一共10个数字,每个数字只能并且一定要出现一次,求它们的全排列。
全排列,举个例子:数字1、2、3的全排列有:123、132、213、231、312、321 一共6种。

如果不知道深度优先搜索算法,看到这道题可能第一反应可能是使用枚举,那么得使用10重循环,并且还要判断10个数字是不是有重复的,我想除非你是个代码狂魔,不然的话你肯定不会去写这个代码。那么有更好的办法吗?of course,这就是典型的深度优先搜索算法(以下简称dfs)题。 在每次选取数字的时候,我们都有10种可能,当然不是每一种可能都能成功,因为我们不能选取重复的数字,那么怎么办呢,我们这里可以采用标记数组的思想,定义一个数组标记0~9一共10个数字的状态(是否被选取),如果当前数字已经被选取那么筛选下一个数字,否则的话就选择当前的数字,下一步仍然采取这种筛选方法(很明显是个递归的思想),那么我们脑子里就可以架构出大概的代码结构:

代码语言:javascript
复制
for(int i = 0; i < 10; i++)
{
    if(book[i] == 0) // 假设标记数组值为0代表这个数字没有选过
    {
        book[i] == 1; // 这个数字被选了,标记
        筛选下一步的数字
    }
}

那么我们的选择什么时候结束呢?当然是我们的数字都被选完了的时候,由此我们需要加一个变量来记录我们选择的数字个数。由此我们可以架构出大致的代码:

代码语言:javascript
复制
void dfs(int step)
{
    /*
    * 当筛选完最后一个数字时返回,
    *(注意不是9,因为第9位数字是最后一个数字,但是此时还没筛选完第9位数字)
    */
    if(step == 10)  
    {
        输出且返回
    }
    for(int i = 0; i < 10; i++) //否则继续循环筛选
    {
        if(book[i] == 0)
        {
            book[i] = 1;
            dfs(step + 1); // 筛选的步数加一
        }
    }
}

这样的话我们把大致的代码思想已经架构出来了,但是现在还有一个问题:上面代码的book标记数组只有将数字标记为已经被选择状态的部分(book[i] = 1;),但是当我们下一次要筛选的时候这个数字不是用不了了吗?如果你也想到了这个问题,那么恭喜你,你已经理解了这道题的思路,在每一轮筛选结束之后,我们在确实要将选中的数字取消标记,这样才能进行下一轮的筛选(注意是下一轮而不是下一步)。那么,我们再加上数字取消标记的代码:

代码语言:javascript
复制
void dfs(int step)
{
    /*
    * 当筛选完最后一个数字时返回,
    *(注意不是9,因为第9位数字是最后一个数字,但是此时还没筛选完第9位数字)
    */
    if(step == 10)  
    {
        输出且返回
    }
    for(int i = 0; i < 10; i++) //否则继续循环筛选
    {
        if(book[i] == 0)
        {
            book[i] = 1;    // 标记数字已经被使用
            dfs(step + 1);
            book[i] = 0;    // 结束这一轮的筛选之后,对用过的数字取消标记用于下一轮筛选
        }
    }
}

题目要求我们输出啊,那么数字的储存和结果的输出在哪里进行呢,到了这一步这些都不难了,下面给出完整的代码:

代码语言:javascript
复制
#include <iostream>
using namespace std;

const int n = 10;   // 一共10个数字
int a[n];   // 储存数字用的数组
int count;  // 符合条件的结果总数
int book[10];   // 标记数组,初值全为0

void dfs(int step)
{
    if(step == n)   // 如果筛选完最后一个数字
    {
        count++;    // 结果数加一
        for(int i = 0; i < n; i++)  // 输出这个符合条件的排列
        {
            cout << a[i];
        }
        cout << endl;
        return ;    // 这句返回语句最好有,不然会增加程序执行所耗费的时间
    }
    for(int i = 0; i < n; i++)
    {
        if(book[i] == 0)
        {
            book[i] = 1;    // 标记数字已经被使用过
            a[step] = i;    // 储存数字
            dfs(step + 1);  // 筛选下一步
            book[i] = 0;    // 对使用过的数字取消标记,供下一轮筛选使用
        }
    }
}

int main()
{
    dfs(0); // 从第0步开始筛选
    cout << count << endl;  // 输出结果总数
}

Ok了,这就是深度优先搜索最基本的模型:

代码语言:javascript
复制
/*
* 深度优先搜索:每一次利用递归将当前情况搜索到最深处(一条道走到黑,不撞南墙不回头),然后利用循环枚举出所有当前可能的情况
* 递归:做好当前怎么做,下一步怎么做和当前是一样的情况
*
* 模型:void dfs(int step)
*       {
*           判断边界,是否返回
*           for(int i = 0; i < n; i++)  尝试每一种可能(有些并不会成功)
*           {
*              尝试成功则继续下一步递归:dfs(step + 1);
*           }
*           返回
*       }
*/

运行结果:

这里写图片描述
这里写图片描述

好了,大功告成。 如果对过程仍然不是很清楚可以把1、2、3一共3个数字带入代码走一遍过程就行了。如果有不正确之处还请指正。 谢谢观看。。。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年01月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档