| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 4.4 DFS -> 正文阅读 |
|
[数据结构与算法]4.4 DFS |
4.4 DFS黑书的这一章节和上一章节一样汇总了DFS部分的知识和内容。 4.4.1 DFS和递归上一章已经介绍过了BFS和DFS两种算法思想,我们这里就直接看hdu1312使用DFS的解法。
肉眼可见的可以发现DFS的代码要比BFS的代码简单一些。 4.4.2 回溯与剪枝还记得我之前手绘的DFS运行的概念图么?DFS搜索的基本操作是选取一个方向的路径进行不断地扩展。 但是在很多情况下,用递归枚举所有的路径可能会因为路径上的结点个数太大而超时。由于很多子节点是不符合条件的,于是可以在递归时遇到肯定没法得到正确结果的结点而撤退,即向前回溯。 BFS中最经典的问题是八数码问题,DFS中最经典的即是八皇后问题。但是这个问题,我们在紫书上面的回溯法已经做过详细的讨论,并且黑书这里和紫书并没有太大的区别,于是我们只贴个代码,有需要的回顾那章内容。
如果只需要一个可行的方案,有较为不同的写法,后面有对这种问题的介绍。 poj 2531 “Network Saboteur”给你n个点以及n个点两两之间的间距,求最优的方案将n个点分为两组A,B两组,使得∑Cij (i∈A,j∈B,Cij表示点i与点j之间的距离)最大。 分析:这道题确实可以用深搜去做······,但是事实上用深搜去做就是将所有的方案枚举出来求出∑Cij (i∈A,j∈B,Cij表示点i与点j之间的距离)的值找到一个最大值。 然而我们发现这里所有的方案有多少种?220/2≈520000种,这意味着什么呢?意味着直接枚举子集就能解决这个问题了。 但还是写了深搜的做法。
(我除了枚举子集的做法还看到有一个图论的做法,恐怖如斯emmm) poj 1416 “Shredding Company”给定两个数n和m,要把m拆开成若干个数,求所有拆法中若干个数的和小于n的最大值。其中如果n与m相同,则不必拆分;如果任何拆法都会使得和大于n,输出“error”;如果有多于1种拆法取得最大值,则输出“rejected”。 分析:也是暴力搜索,我在别人博客看到一个暴力搜索的搜索树: 省略号为未列出的结点。 相当于将每两个数之间的空隔看作上一个问题的位数。代码类似就不多做复写了。 poj 2676 “Sudoku”简而言之,解决数独问题。 分析:不断找0填空的深搜,这个问题就是我前面提到的只输出一种答案的结果,dfs返回的类型为bool型,对全局变量进行操作,当遇到一种可行的结果直接返回true。
除了返回bool型,还有用void,返回NULL,用一个全局变量flag的写法,但相较起来会复杂一点。 poj 1129 “Channel Allocation”给定n个节点的无向图,求最少的颜色数量对无向图的节点染色,保证图中相邻的节点颜色不重复。(原题不是这样表述的,我也是翻看的别人的翻译和解析) 分析:这个问题的求解和DFS没什么关系,实际上是一个典型的图着色问题,最优的求解方法不是DFS回溯暴搜,而是贪心: 将无向图的结点按照度数(相邻点个数)递减的次序排列. 用第一种颜色对第一个结点着色,并按照结点排列的次序,对与前面着色点不相邻的每一点着以相同颜色。 用第二种颜色,第三种颜色······对尚未着色的点重复步骤,直到所有点着色完为止。 hdu 1175 “连连看”分析:这个问题我开始的时候想复杂了,以为是要消除掉“连连看”中所有的格子,事实上只是给定你个图,问你这个图中某两个点是否存在一条不超过两个转弯的路径能够连通。 由于需要判断路径转弯的个数,需要增加两个属性,一个属性保存路径上一个节点的运动方向,另一个属性保存路径已有的转弯个数,通过上一个结点的运动方向,修改已有的转弯个数。 这里的写法就是使用全局变量的写法,测了一下比bool函数的写法要快不少:
hdu 5113 “Black And White”有N*M个格子的棋盘,用K种颜色去涂,相邻格子不能同色。给定每种颜色要涂的格子数,如果能满足题意,则输出YES和任意一种涂法,不能输出NO。 分析:从左到右从上到下深搜即可,问题在于如何回溯剪枝,如果对于某个颜色当前剩余的格子数不够进行染色,即当前剩余的格子数/2<某颜色剩余需要染色的格子数,直接return。 代码和上题几乎完全相等就不多做赘述,问题主要在于如何有效的剪枝。 4.4.3 迭代加深搜索对于有些问题,它搜索树的某些分支非常深甚至可能到无穷,搜索树的宽度也极广。如果直接用DFS,可能会陷入DFS某个分支的递归无法返回,直接用BFS,队列空间可能会爆炸。 于是我们可以在每次进行DFS之前,限定DFS的深度,初始化为1,如果深度为1的DFS找不到答案,再进行最大深度为2的DFS······直到找到答案。 这个算法思想我们叫做IDDFS。 4.4.4 IDA*首先要知道的是IDA*是IDDFS的优化,很多博客直接把IDDFS当作了IDA*,A*是BFS算法添加了一个启发函数的优化,IDA*则相当于A*算法思想在IDDFS中的应用。 说简单点就是给IDDFS中的DFS添加一个估价函数来进行剪枝。 poj 3134 “Power Calculus”给定数x和n,求x的n次方,只能使用乘法和除法,算过的结果可以被利用,求最少算多少次。 分析:这道题如果用BFS或者A*求最短路会出现一个问题,就是新的值是指数级的增长,可扩展的方向指数级的增加。直接用DFS,由于没有步骤数的限定,深度很可能过长。 于是考虑用IDA*,估价函数即判断在当前的情况用最快的倍增能否得到n,这道题在紫书竞赛题目选讲那里做到过,不多作赘述。
属于比较简单的一个IDA*。 hdu 1560 “DNA sequence”找到一个最短的序列,使得输入的所有序列都能在这个序列中按照原本序列的顺序依次找到。输出最短序列的长度。 假设给定的“ACGT”,“ATGC”,“CGTT”,“CAGT”,得到的序列如下: 分析:同样的,用DFS不能确定某个分支的深度,至于BFS和A*······(DNA序列只会由ACGT四个字母组成,我也不太清楚有没有优秀的A*解法,搜到一个解法效率好像不如IDA*)。 估价函数比较简单,即是n个序列还没有匹配的位数的最大值。代码如下:
还有一道例题也在竞赛题目选讲那里介绍过了IDA*的解法(我当时还吐槽了一下),也不多做赘述了。 总结总结一下就是,如果要求最优路径考虑用A*(前提是你写的出估价函数),如果需要求出全部的结果考虑用DFS。 如果这个问题搜索树庞大,又宽而且很多分支的深度无法确定,考虑用IDA*(前提也是你写得出估价函数)。 很多博客将IDA*记作A*的优化,事实上A*相当于BFS和贪心的结合,IDDFS相当于不断扩展长度的DFS,即DFS和BFS的结合(我觉得这么说很牵强),IDA*和A*没有太大的关系,只是相当于在IDDFS的DFS过程中添加了一个类似于A*的估价函数来进行剪枝。 我个人认为,如果不是搜索树过宽并且深度不确定,就不要考虑用IDA*了。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 8:43:49- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |