您的位置:首页 > 其它

DFS深度优先搜索算法

2015-12-13 16:15 267 查看
DFS算法全英文名为:Depth First Search,中文名字叫做深度优先搜索,它的基本思想是沿着树的深度遍历树的节点,尽可能深的搜索树的分支,当该节点的所有边都已经被探寻过,那么就回溯到离这节点最近的之前的节点,然后继续这一步骤,知道所有的可能性都被遍历出来之后就可以了,该思想类似于回溯法,从最深度起一层一层的遍历然后回溯。

DFS的关键在于解决“当下应该如何做”,当下这一步做好了之后,对后续的步骤就依葫芦画瓢,与当下如何做是一样的。比如,我们将几个不同的扑克牌放入几个盒子里面,那么根据全排列我们可以知道有很多种方法,如果让我们来求出所有的访法的话,我们只需要解决当下如何做,也就是如何去放,我们可以使用循环语句来将扑克牌放入盒子里,然后使用一个中间数组来判断扑克牌是否已经被放入,这样就解决了如何放的问题,然后后面就可以根据相同的方法来求出另外几种不同的方法,然后就求出所有的方法了呗。下面的代码就是深度优先搜索的基本模型:

void dfs(int step)

{

//判断边界

if(step==n)

{

….

return ;

}

//尝试每一种可能
for(...)
{
//判断是否被访问等等
if(book[i]==0)
{
...
//标记已经访问等等
book[i]=1;
//使用递归的方式继续下一步
dfs(step+!);
//重新设置该店为未访问,重新下一次尝试
book[i]=0;
}
}

return ;


}

下面我们来举几个例子,

Q1.扑克牌的放置(全排列问题):假如有编号为1/2/3的三张牌,和编号为1、2、3的三个盒子,现在需要将这三张扑克牌分别放于不同的盒子里面,并且每个盒子里面只能放一张牌,那么一共有多少种放法呢?

A1.根据DFS的基本思想来看,我们可以这样来做:

1.先将一号牌放于一号盒子,再将二号牌放于二号盒子,再将三号牌放于三号盒子;然后我们发现手里的牌和盒子都刚好用完了。

2.然后我们在到三号盒子那里将三号牌取出来,手里只有一张三号牌,还剩一个三号盒子,然而三号牌刚放过三号盒子了,所以我们不放。

3.在到二号盒子面前讲二号牌取出来,我们发现手里面有两张牌,因为刚才二号对应二号盒子,三号对应三号盒子,因此我们不能重复放了,这次我们将三号牌放于二号盒子,将二号牌放于三号盒子,

4.然后我们又重复步骤2和3,然后我们取出一号盒子的牌,同理,几号盒子之前已经对应几号牌放置了,这次我们在一号盒子放入2号牌(因为我们在循环的时候是从1到最后的数的,因此我们这里放的是2号而不是1号,当然,主要的不是顺序问题,还有一个就是他们两个都是还未放置状态),

5.然后我们就这样重复下去,最终我们可以得到所有放置的可能性。

分析DFS的基本模型内容:
1.边界:
这里dfs函数的参数step代表的是当前所要放置和盒子的位置,因此这里的搜索边界应该是step>3,也就是step>n
if(step>n)
return ;
2.尝试每一种可能:
我们是将扑克牌放于盒子里面,因此我们要尝试每次将当前扑克牌放入当前盒子里面:
for(int i=1;i<=3;i++)
{
if(book[i]==0)
{
a[step]=i;
book[i]=1;
}
}
在这里book数组是用来标记当前位置的扑克牌是否已经被放入,我们设置为0为未放入,1为已放入

3.递归继续下一步:
在这里继续下一步也就是继续下一个盒子的放入,我们可以在刚才的循环语句里面加入递归:
for(int i=1;i<=3;i++)
{
if(book[i]==0)
{
book[i]=1;
a[step]=i;
dfs(step+!);
}
}
4.在这里如果当前排序尝试完了,这会是什么情况呢?从上面的代码我们可以看出,当尝试第一次尝试完毕之后,第一个排序使出来了,但是book数组里面的值全部都变成1也就是变成所有的扑克牌已经被放入了,那么就是说循环语句的条件book{i]==0变成了矛盾式。因此我们需要在每次尝试完毕之后将book数组的元素都重置。但这样也不好,因为如果每次全部重置的话,那么我们就无法得到只有一两个数变化的排列了,比如我们得到了123之后直接将数组book重置为0,那么我们就无法得到132这种排序方式了,因此我们可以在每次尝试完毕之后将上一次的book标记重置为0,以便于下次继续使用,也就是在递归DFS之后重置book[i]=0;:
for(int i=1;i<=n;i++)
{
if(book[i]==0)
{
a[step]=i;
book[i]=1;
dfs(step+!);
book[i]=0;
}
}
//最后返回
return ;


下面给出这个问题的完整代码:

#include
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: