国科大算法分析与设计 陈玉福_算法分析与设计之-搜索策略

47b20c0a4a55884784b186c10d8aade6.png

搜索策略是算法分析与设计中很常见的一种算法思想,特别是对于很多多项式时间内无法解决的问题,即NP-完全问题。而通常这些实际应用中的NP-完全问题都具有比较小的输入规模,此时一种很自然的想法是穷举问题的解空间,从中找出问题的解。

这篇文章会讲解常用的深度优先搜索广度优先搜索分支界限搜索A*搜索等。

  1. 深度优先搜索

深度优先搜索说白了就是一直走到头,直到找到最优解。算法基本思想如下:

cd3b56f99bacf1c167e9f4a538abfede.png

关于深度优先搜索可以用来实现,也可以用递归来实现。

可以参考图的深度优先搜索代码。

2. 广度优先搜索

广度优先搜索说白了就是每一步得走遍所有可能的点,直到找到最优解法 。

c30c1919fdc75477236dc1bb16b70473.png

关于广度优先搜索,可以用队列来实现,可以参考图的广度优先搜索算法。

3. 爬山法-优化的深度优先搜索

深度优先搜索的过程中,我们经常遇到多个节点可以扩展的情况,首先扩展哪个?爬山法是一种优化的深度优先搜索,使用启发式测度来排序节点扩展的顺序、使用贪心思想确定搜索的方向,基本思想如下:

69c613f10e59cee4d2472b6bb9be88e5.png

例如在8-puzzle问题中采用爬山法的思想:

6bba6142a6e3465f4a3ea677e78c4c12.png

b143620e39b447f743892667a5546223.png

4. Best-First策略-结合深度优先搜索和广度优先搜索

Best-First策略是根据一个评价函数

equation?tex=f%28n%29 ,在目前产生的所有节点中选择具有最小评价函数值的节点进行扩展。它结合了
深度优先搜索广度优先搜索的优点,具有 全局化观念,而爬山法仅仅具有局部优化观念。

ef805f7235d44c573e8dca9e56c14aeb.png

同样用8-Puzzle例子来说明,评价函数用的是

equation?tex=f%28n%29+%3D+w%28n%29 ,其中
equation?tex=w%28n%29 表示节点
equation?tex=n 中处于错误位置的方块数,

c4de0ced94f0d3b6b2f50f47b3602a9a.png

可以看到Best-First策略使用来选择每次扩展的节点,不像爬山法只是一个带贪心思想的深度优先搜索Best-First策略融合了深度优先和广度优先的优点!

5.分支界限搜索

分支界限搜索的基本思想是用某种策略(比如爬山发、Best-First策略)产生分支,发现优化解的一个界限,缩小解空间,从而提高求解的效率。说白了就是剪枝呗!

例如使用分支界限搜索来求解多阶段图的例子:

例1:多阶段图的搜索问题:

6f268304ecb49fb6b247433bab8f80d6.png

首先将问题转化为树搜索问题,

be81da624424c56a535ecce7d2d423bd.png

接受使用爬山发策略进行分支界限搜索

88bd17878089b4085fa568c88189248d.png

例2:人员任务分配问题。该问题定义如下:

4eb2774a501a663263f04c0f318229b5.png

379a2f1210565b6ccd07250414e6e595.png

将该问题转化为树的搜索问题,问题的解空间是一个拓扑排序。如下是拓扑排序算法的定义,

f0edab9ad609ece16ce32321977b2e36.png

该问题的解空间是所有拓扑排序的序列集合,每个序列对于一个可能的解。将问题的解用树表示如下:

7b7296e3bbbabae90d1940dde2331e0f.png

该拓扑序列树的生成算法伪代码如下:

ce2a806ad3f62f36b3a84e5fd22b82f3.png

接下来需要计算解的代价的下界:

d4e5ebc466c639c489fc98a6a032c2b3.png

例如:

e8da4322aa63ab503cd4ac31185e9ef1.png

由此得到解的加权树表示如下:

668de543ca71ced71eb1316b3bb8862a.png

使用爬山法策略进行分支界限搜索算法如下:

f47db7e3446a98cc28010962fbb8a2f7.png

f06455b4496c7752af5ff99182d99b53.png

例3:旅行商问题

旅行商问题定义如下:

bc243c847fab002a8ac8bea2c2d93f20.png

将该连通图用矩阵表示如下,即代价矩阵

equation?tex=Cost%28i%2Cj%29

a43f7c761c7f7c109eac658521466194.png

为了方便,将该问题转化为一个树搜索问题(个人反倒觉得这个地方技巧性很强):

389460f1a0fd58639308591ba54e4f6b.png

构造根节点,其为包含所有点的解集合,其权值为代价下界,计算代价下界如下:

54dc6e93c76217f676bb77abb03b3bf4.png

代价下界为:

equation?tex=3%2B4%2B16%2B7%2B25%2B3%2B26%2B4%2B1%2B7+%3D+96 .

1503ab2d2d9a4ec126b79daab2e8eace.png

变换后的代价矩阵为:

f24a376a17bd460beafd2fd0181922bd.png

每次划分的时候,选择这样的边,满足:

153b9e47ed961d3a37f48f9a97407264.png

即选择使子节点代价下界增加最大的那个划分边,以此来构造根节点的两个子节点,左子节点为包括该边的所有解的集合右子节点为不包含该边的所有解的集合

例如对于根节点,

计算使得左子树代价增长为0时,右子树代价下界的增长值

equation?tex=f%28i%2Cj%29 ,选择代价下界增长最大的那条边:

cc4264860f0ef4fc4a2490554887d3a7.png

所以选择边

equation?tex=%284%2C+6%29 ,此时树变为:

a51f0c1dc15b0d971e329e899f0bc035.png

计算左右子节点的代价下界(私以为这一步有点多余):

131c9e5127929a49d3cd5b3a0424be27.png

此时树变为:

e9f12af3274db7fb266897ab3f6134bf.png

接着就是递归的构造左右子树了!

首先构造左子树对应的代价矩阵:

0fdeebb57315a992c716adc4f2dfce2e.png

计算左子树的根的代价下界:

7717193221419daa7b39415a6952bfc1.png

构造右子树根对应的代价矩阵:

91384a2848b85e30b3feb372d0378ed7.png

742797382dbf228e2adaf06138c0f54d.png

52e5963055ed1ee9ecbd4ab8ed558de4.png

以此类推,一直往下扩展,最后集合为空找到最优解!

9a49d76e02bab067d202669e61a7ebe4.png

另外注意搜索过程中避免出现环的问题:

729a89ae33fbcad8056bd6e5060b0b1d.png

例4:0-1背包问题

09ae8bf979e5ddc10ce7c4592b8d9436.png

考虑到用搜索的方法,那么怎么将问题表示成树搜索问题呢?

f23fdbcb43d6583ccc79b2feddade702.png

扩展每个节点的时候计算节点的下、上界:

c148f06dc3facd1d26cb973f8393d8c9.png

483ca8b32c53127ae47ff33c7dbedc6d.png

分支界限搜索寻找最优解:

9b3d6f5369124df1d4bc1d5dcfcc08f2.png

例如下面构造0-1背包问题的搜索实例:

f4795ca8872501949e213d03f59a55ca.png

第一个物品的取舍:

b7b6d6382f88bfa223a9f7ddb7377504.png

树变为:

85c2b236545ccae85fa8ca9ba9a01e07.png

第二个物品的取舍:

44ac699d4848a23a0227ebbd58919c47.png

树变成:

92a1834d25451eec3f0d7b5daeda85ad.png

依次类推,第三个物品的取舍,得到的树为(灰色表示剪枝的):

27025634eeb3ba6aa2c9e29b945882cf.png

9770293a1d1c7c3f34725e46780c2f35.png

故,最终的最优解为220.

6.A*算法

A*算法是利用启发式函数Best-first策略进行搜索从而更早的发现优化解的一种算法,它的核心告诉我们在某些情况下得到的解一定是最优解,算法可以停止!与分支界限不同的是:分支界限是为了剪掉不能达到优化解的分支。

A*算法的关键是启发式函数的选取!对于任意一个节点

equation?tex=n ,我们有:
  • equation?tex=g%28n%29 = 从树根到
    equation?tex=n 的代价
  • equation?tex=h%5E%2A%28n%29 = 从
    equation?tex=n 到目标节点的优化路径的代价
  • equation?tex=f%5E%2A%28n%29+%3D+g%28n%29+%2B+h%5E%2A%28n%29 是节点
    equation?tex=n 的代价

上述式子中

equation?tex=g%28n%29 好理解,可是
equation?tex=h%5E%2A%28n%29 怎么计算呢?一般的,可以使用某种方法来估计
equation?tex=h%5E%2A%28n%29 ,用
equation?tex=h%28n%29 表示
equation?tex=h%5E%2A%28n%29 的估计,
使得
equation?tex=h%28n%29+%5Cleq+h%5E%2A%28n%29 总为真
,通常把
equation?tex=h%28n%29 叫做
启发式函数

为什么要保证

equation?tex=h%28n%29+%5Cleq+h%5E%2A%28n%29 的估计规则呢?这个其实和A*算法的本质有关!

A*算法的本质-已经发现的解是优化解!说白了当使用Best-first策略搜索树的时候,如果A*算选择的节点是目标节点,那么该节点表示的解就是优化解,算法可以停止了!!!

具体看下面的证明:

f72b2c86643cf138db5c88c3ea4345bc.png

因此,总结A*算法的规则如下:

e79de53097128fd2f2765e20401e7c11.png

例子:应用A*算法求解最短路径问题-求S->T的最短路径

55e00eb905d720f4fef6b69a4db367cd.png

算法执行过程如下:

701ecea7d23ec2f98f739f0817910650.png

所以接下来扩展

equation?tex=V1

604296c1d42951f9f43cb2a003fb231d.png

接下来扩展

equation?tex=V2

f1937c5f2a5f4d49e358a151aad29eee.png

接下来扩展

equation?tex=V4

e5c1e11b24e65440e3b12dd61ceac71a.png

接下来扩展

equation?tex=V3

b2ef3c004587f8206c0c0d953506ee7b.png

接下来扩展

equation?tex=V4

500ca7789480bdd49552a97ce1ea0719.png

接下来扩展

equation?tex=T

095708f350d4af6992be04a54c34b55b.png

这里细心的话会发现

equation?tex=V4 节点扩展了两次,也就是说将节点添加到list中的时候,需不需要比较两个重复添加的节点的代价保留小的那个,也就是“剪枝”一下?有点疑惑,A*算法中剪枝策略是不是必须的?

另外又有一个用漫画的形式来讲解的A*算法很是形象生动,参考

漫画:什么是 A* 寻路算法?​mp.weixin.qq.com
715a619085b7694e560d39361423d8d9.png

小结:至此,我们讲解了搜索策略中的常用的深度优先搜索广度优先搜索爬山法Best-First策略分支界限搜索以及A*算法,快快将该思想应用到你的coding中吧!


参考资源

【1】哈工大骆吉洲《算法分析与设计》课程PPT

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值