深度优先搜索---一个懵逼的东东

深度优先搜索属于图算法的一种,英文缩写为DFS即Depth First Search.其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.(来自百度百科)

先解释以下深度:

深度指在搜索的过程中沿着一条路一直向下进行,直到这条路没有下一个节点停止,然后返回到上一步接着进行上述操作

所以深度优先搜索的整体结构就是:

1.递归2.剪枝

可能这样说有点不清楚,举个例子

打印1-4的全排列开头为1和2的所有序列;

1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1

上述是由编译器进行深搜算法打印的1-4的全排列开头为1和2的所有序列

下面是运行的代码

#include<bits/stdc++.h>
using namespace std;
int n,pd[100],used[100];//pd是判断是否用过这个数
void print()//输出函数
{
    int i;
    for(i=1;i<=n;i++)
    printf("%5d",used[i]);//保留五位常宽
    cout<<endl;
}
void dfs(int k)//深搜函数,当前是第k格
{
    int i;
    if(k==n) //填满了的时候
    {
        print();//输出当前解
        return;
    }
    for(i=1;i<=n;i++)//1-n循环填数
    {
        if(!pd[i])//如果当前数没有用过
        {
            pd[i]=1;//标记一下
            used[k+1]=i;//把这个数填入数组
            dfs(k+1);//填下一个
            pd[i]=0;//回溯
        }
    }
}
int main()
{
    cin>>n;
    dfs(0);//注意,这里是从第0格开始的!
    return 0;
}

我们通过上述举例以及举例所用代码来进行分析:

比如我们发现输出的第一行是1 2 3 4,第二行是1 2 4 3

为什么一行会输出四个数字?是因为剪枝,即在递归函数中下一个判定条件,也就是深搜搜索到这一步已经没有路能走了

上边解释剪枝可能有点笼统,简单的说就是走到这,不能往下走了

为什么要有剪枝呢?很显然根据剪枝的定义,就是避免遍历的时候越界,或者去掉影响结果的因素

第二个问题,为什么第一行是1 2 3 4,而第二行是1 2 4 3?

因为在其中进行递归操作,在这先说一个标记数组,这个数组作用是,对所已经便利过的数进行标记,下来我们看下标记数组的记录过程

我们开始运行程序输入4:

进入dfs(0),dfs()中系数表示已经确定几个数的输出,下来遍历1-4发现pd[1]=0,标记1,即pd[1]=1,used[1]=1

下来进行dfs(1)遍历1-4发现used[1]=1,跳过,下一个pd[2]=0,标记2,即pd[2]=1,used[2]=2

依次一直到dfs(4)遍历时发现,满足剪枝条件,输出第一行1 2 3 4

下来进行递归的回溯操作,即在dfs(3)的时候我们标记pd[4]=1;现在回溯pd[4]=0,这样在dfs(3)中的for遍历结束

下来到了dfs(2)是for遍历到i=3的时候进行的上面的dfs(3)的递归结束,所以回溯pd[3]=0,此时dfs(2)中的i=3结束,进行i=4遍历的pd[i]=0,所以used[2+1]=4,即pd[4]=1;

下来进行dfs(2)是i=4的dfs(3)递归,当i=3时pd[i]=0,所以used[3+1]=3,pd[3]=1,下来进行dfs(4)递归

此时达到剪枝边界,进行输出,得到1 2 4 3

然后下来进行..........

算了不写了,太累了,剩下递归,剪枝,回溯按照上面的步骤进行即可

简单的说就是

dfs(k)
{
        if(k==n)剪枝      for()遍历所有,和上面if没关系
        {
            如果未标记
            {
                标记
                dfs(k+1)递归
                回溯
            }
        }
}

如果遍历的是图,那么就是遍历相同深度未标记的子节点,具体题目中如何使用看下https://www.cnblogs.com/RE-TLE/category/1531861.html里面的题目以及题解

以上来自一个练习时间长达一年的蒟蒻Acmer,有事您Q我,我一直在de

原文地址:https://www.cnblogs.com/RE-TLE/p/11392688.html

时间: 2024-08-27 16:24:45

深度优先搜索---一个懵逼的东东的相关文章

一个考试模拟界面——先记录一下下ui上的东东

先上图,有图有真相 要记录的有以下几点: (1)如何给控件widget加背景图片 (2)如何改变控件中的字体大小,如何让界面中字体都改变 (3)如何构造除了这么漂亮的布局呀,这一点上还是很骄傲的!嘿嘿... (4)在python2.7编写出的界面上显示中文 Part1: 还是先写如何布局吧..按照时间顺序来.. 在pyside中,关于layout,已经接触的有:QtGui.QVBoxLayout(竖直向下的),QtGui.QHBoxLayout(横向的),这两天接触到了一个QtGui.QGrid

一个例子,关于航班线路的深度优先搜索

1 java 代码,摘自<java 编程艺术> 2 3 /** 4 * 航班信息类 5 * 用于存放航班线路 6 * @author shiyan 7 * 8 */ 9 public class FlightInfo { 10 String from;//出发城市 11 String to;//目的城市 12 int distance;//距离 13 boolean skip;//回退标志 14 public FlightInfo(String f,String t,int d){ 15 th

一个祸害我很久的东东——事件过滤器之按键触发

下面这个东东其实很常见,也很实用,平时上网的时候对之经常见,以为很简单,当然弄懂后,其实发现,他确实蛮简单的,但就是这小东西害了我好久好久啊.... 就是在很多页面中,我们按下特定的键就会触发特定的功能,如果是按下按钮的话,其实还蛮简单的,但是,比如当你输入在输入银行卡号的时候,尤其是电话输入的时候,没有界面上的按钮让你按,一般银行是“请输入银行卡号,以#结束”,当然我不知道,银行用的是什么系统,我只是说自己模拟这个功能的时候,发现其实还蛮伤脑筋的... 不多说,先上代码再解释: from Py

castle problem——(深度优先搜索,递归实现和stack实现)

将问题的各状态之间的转移关系描述为一个图,则深度优先搜索遍历整个图的框架为:Dfs(v) {if( v 访问过)return;将v标记为访问过;对和v相邻的每个点u: Dfs(u);}int main() {while(在图中能找到未访问过的点 k)Dfs(k);} 4例题:百练2815 城堡问题? 右图是一个城堡的地形图.请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大.城堡被分割成m×n(m≤50,n≤50)个方块,每个方块可以有0~4面墙.5输入输出? 输入? 程序从标准输入设备

终于明白了main(int argc,char *argv[])是个神马东东

以前看到有main(int argc,char *argv[])的程序都需要在dos命令状态下输入命令,也不知道dos怎么打开,所以一直没尝试,今天又碰到一个,所以决定学习一下. 首先写好我的程序,我的是vs2008.程序如下: #include<stdio.h> void main(int argc,char *argv[]) { while(argc>1) { ++argv; printf("%s\n",*argv); --argc; } } 其实这就是课本上的一

深度优先搜索与广度优先搜索算法理解

深度优先搜索算法和广度优先搜索算法是图论中两个有意思也很实用的算法,下面我们来看看这两个算法. 严书中,给出的利用深度优先搜索(Deep First Search)算法进行图的遍历伪码如下 1 Boolean visited[MAX]; //标志数组 2 Status (*VisitFunction)(int v); //访问函数 3 4 void DFSTraverse(Graph G, Status (*Visit)(int v)) 5 { 6 VisitFunction = Visit;

图论 深度优先搜索 广度优先搜索的非递归实现

深度优先遍历 1.深度优先遍历的递归定义 假设给定图G的初态是所有顶点均未曾访问过.在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过:然后依次从v出发搜索v的每个邻接点w.若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止.若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止. 图的深度优先遍历类似于树的

深度优先搜索

在图中的深度优先搜索,由于避免回路的产生,设置visit数组. 有两种深度优先的应用场景.一种是用于最优解的寻找,即到达目的地的最优解.这时需要设置全局的一个数组,还有变量,来储存路径.通过与别的方法的比较,获取最优解. 第二种是染色问题,只要求全部遍历,没有最优的要求. 还有哈希的用法.当需要记录拥有共同数字特征的一些属性时,就可以使用哈希数组.使用时按照属性的含义寻找.如二叉树某层的数量.

深度优先搜索(dfs)

关于深度优先搜索的总结: 1 dfs 的基本结构:  void dfs(int x){ if( x 超出边界){ return ; }else{ for(遍历){ if(未访问过){ 访问         ; 打上标记    ; dfs(x + 1) ; 去掉标记    ; //极易忘记 } } } return; } 2 用dfs求全排列: 本来好好的,结果sizeof(pointer) 就完蛋了.神秘的内存错误,而且还能正常的跑出一个不正常的结果出来. 想了解sizeof这个小妖精的看这里