深度、广度和双向搜索优化及其应用

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

影响搜索效率的因素

两个状态的集合
: 未处理完的状态 : 已处理的状态



判重:每次演化出一个状态s时,s是否属于 或者 剪枝:状态s的任意演化结果是否都属于

属于,则剪枝

演化出来的状态数量:的大小
深度优先搜索



两个状态的集合 : 未处理完的状态 : 已处理的状态 从中选择被演化状态的原则:离初态S0最远的状 态s S0到s的距离:从S0到达s使用的动作数量 实现方法:用stack表示 每次取stack顶部的状态演化 每次演化出的状态s若不属于,则s将压入stack 的顶部
搜索

有顺序有策略地产生解空间的元素
每个解空间的元素表现为一定动作的执行轨迹 (trace of actions) 采用递归的策略产生解空间的元素,出口条件 轨迹已经达到终点:真解、或者伪解 轨迹不可能导出真解


搜索的过程



两个状态的集合 : 未处理完的状态 : 已处理的状态 状态的处理: 有顺序的尝试备选动作, 每一次的尝试都 演化出另一个状态 已处理的状态: 全部备选动作都已经尝试 一个树结构: 状态之间的演化关系 递归的出口 为空 演化出目标状态S* 演化出的状态不属于
深搜 vs. 广搜
深搜 1-2-4-8-5-6-3-7

广搜 1-2-3-4-5-6-7-8

广搜算法

广度优先搜索算法如下:(用 QUEUE)
(1) 把初始节点S0放入Open表中; (2) 如果Open表为空,则问题无解,失败退出; (3) 把Open表的第一个节点取出放入Closed表,并记该节点 为n; (4) 考察节点n是否为目标节点。若是,则得到问题的解, 成功退出; (5) 若节点n不可扩展,则转第(2)步; (6) 扩展节点n,将其子节点放入Open表的尾部,并为每一 个子节点设置指向父节点的指针,然后转第(2)步。
问题

是否还有新的剪枝策略,以进一步加速搜 索过程?
剪枝 4

拼每一根棍子的时候,应该确保已经拼好 的部分,长度是从长到短排列的
由于取木棒是从长到短的,所以如果长得 在前,短的在后不可行的话,那么相反的 一定不可行

POJ1020-Anniversary Cake


有一块边长为BoxSize的正方形的大蛋糕, 现在给出n块不同尺寸的正方形的小蛋糕的 边长,问是否能把大蛋糕按恰好切割为这n 块小蛋糕,要求每块小蛋糕必须为整块。 Max_n=16,Max_size=10,大蛋糕最大40*40 如何确定搜索策略
POJ1077八数码问题

八数码问题是人工智能中的经典问题 POJ1077八数码Baidu Nhomakorabea题:经典搜索问题

有一个3*3的棋盘,其中有0-8共9个数字,0表 示空格,其他的数字可以和0交换位置。求由初 始状态 到达目标状态 123 456 780 的步数最少的解?
8
2
3
1
2
3
1
4
6
4
5
6
5
7
7
8
1
搜索
深度优先搜索 广度优先搜索
枚举

划分解的存在范围 对范围内的元素进行逐一判断 例:求出A~I 分别对应的数字(1~9) 使得下 式成立 ABCD
× E
FGHI
枚举解法

枚举ABCDE的值,计算乘积,判断是否符 合要求。
搜索复杂的、高级的枚举

枚举: 解空间中的每个元素是一个动作(action)的 集合F
剪枝2

让我们考虑接下来的两种策略,一是用更长的木 棍来代替当前木棍,显然这样总长度会超过原始 木棍的长度,违法。二是用更短的木棍组合来代 替这根木棍,他们的 总长恰好是当前木棍的长度, 但是由于这些替代木棍在后面的搜索中无法得到 合法解,当前木棍也不可能替代这些木棍组合出 合法解。因为当前木棍的做的事这些替 代木棍也 能做到。所以,当出现加上某根木棍恰好能填满 一根原始木棍,但由在后面的搜索中失败了,就 不必考虑其他木棍了,直接退出当前的枚举。
剪枝3

如果某次拼接选择长度为L1的木棒,导致最终失 败,则在同一位置尝试下一根木棒时,要跳过所 有长度为L1的木棒。
小结



构造一条木棒长度为L的“路径”:拼接木棒 在未被拼接的木棒中,找出一节最长的,开始拼接 从未拼接的木棒中,选择一个长度合适的木棒,使得拼接 后的木棒长度≤L 找到了 若在前面的拼接过程中曾试图用过相同长度的一节 其他木棒,但发现这样拼接不成功,继续寻找能够 进行拼接的木棒 //剪枝3 把找到的那节木棒拼接上去。继续进行拼接 继续拼接成功,找到了“路径” 继续拼接不成功,把刚拼接的那节木棒拿下来, 继续找下一个合适的未拼接木棒 //剪枝2、1 没有找到:拼接失败
If (num>size-col[p]) num=size-col[p]; For i:=num downto 1 do if (a[i]>0) Begin dec(a[i]); For j:=p to p+i-1 do inc(col[j],i); If (dfs(t+1)) exit(true); For j:=p to p+i-1 do dec(col[j],i); Inc(a[i]);
在前面,后进入Open表的节点排在后面。
广度优先搜索



两个状态的集合 : 未处理完的状态 : 已处理的状态 从中选择被演化状态的原则:离初态S0距离最近 的状态s S0到s的距离:从S0到达s使用的动作数量 实现方法:用queue表示 每次取queue头部的状态演化 每次演化出的状态s若不属于,则s将压入 queue的尾部


Dfs递归搜索函数


Bool Dfs(int nUnusedSticks, int nLeft ) ;
Function dfs(nUnusedSticks:longint, nLeft:longint):longint

表示: 当前有nUnusedSticks根未用木棒, 而且当前正在拼的那根棍子比假定的棍子 长度短了nLeft, 那么在这种情况下能否全部 拼成功。
解题思路

搜索题,还要解决一个问题:如何剪枝 就本题而言,即尽可能快地发现一根拼好 的棍子需要被拆掉,以及尽量少做结果不 能成功的尝试。
剪枝1


每次开始拼第i根棍子的时候,必定选剩下的木棒 里最长的一根,作为该棍子的第一根木棒。 即:就算由于以后的拼接失败,需要重新调整第i根 棍子的拚法,也不会考虑替换第i根棍子中的第一 根木棒(换了也没用)。如果在此情况下怎么都 无法成功,那么就要推翻第i-1根棍子的拚法。如 果不存在第i-1根棍子,那么就推翻本次假设的棍 子长度,尝试下一个长度
解题思路

在拼接过程中,要给用过的木棒做上标记, 以免重复使用 回溯:拼好前i根棍子,结果发现第i+1根拼 不成了,那么就要推翻第i根的拼法,重拼 第i根…..直至有可能推翻第1根棍子的拼法

解题思路

搜索题,首先要解决一个问题:按什么顺 序搜索? 把木棒按长度排序。每次选木棒的时候都 尽量先选长的。 因为短木棒比较容易用来填补空缺。一根 长木棒,当然比总和相同的几根短木棒要 优先使用
我们的搜索顺序保证了底部先填满的原则, 如果悬空,则回溯

Functin dfs(t:longint):boolean Begin If (t=n+1) exit(true); P:=1;num:=0; For i:=1 to size do if (col[i]<col[p]) p:=I;
For i:=p to size do if (b[i]=b[p]) inc(num) else break;

将初态S0变换为另一个状态F(S0) F中各动作的执行顺序不影响F(S0) 如果F(S0)是符合要求的S*, 那么F是真解, 否则是 伪解
搜索复杂的、高级的枚举

搜索: 解空间的每个元素是一个动作的序列F 将初态S0变换为另一个状态F(S0) 如果F(S0)是符合要求的S*, 那么F是真解, 否则是 伪解 有一个规则, 确定在每个状态S下,分别有哪些动 作可供选择 采用递归的办法, 产生每个动作序列
Dfs的基本递推关系:



bool Dfs(int nUnusedSticks, int nLeft) { ….. if( nLeft = 0 ) //一根刚刚拼完 nLeft := L; //开始拼新的一根 找一根长度不超过nLeft的木棒(假设长 为len)拼在当前棍子上,然后 exit Dfs(nUnusedSticks – 1, nLeft – len ); }
POJ1011 木棒问题

问题描述:

乔治拿来一组等长的棍子,将它们随机地裁断(截 断后的小段称为木棒),使得每一节木棒的长度都 不超过50个长度单位。然后他又想把这些木棒恢复 到为裁截前的状态,但忘记了棍子的初始长度。 请你设计一个程序,帮助乔治计算棍子的可能最小 长度。每一节木棒的长度都用大于零的整数表示
2 8 3 1 4 7 6 5
S0
2
2 8 3 1 4 7 6 5
3
2 3 1 8 4 7 6 5
4
2 8 3 1 6 4 7 5
5
2 8 3 1 4 7 6 5
6 8 3 2 1 4 7 6 5 14 8 3 2 1 4 7 6 5
End;
End.
广度优先搜索

广度优先搜索也称为宽度优先搜索,它是一种先 生成的节点先扩展的策略。适合于判定是否有解 和求唯一解的情况


搜索过程是:从初始节点S0开始逐层向下扩展,在第n层节点还没 有全部搜索完之前,不进入第n+1层节点的搜索。 假设有两个表:Open表存放待处理节点,Closed表存放处理完节 点 Open表中的节点总是按进入的先后排序,先进入Open表的节点排
Dfs的终止条件之一:

bool Dfs(int nUnusedSticks, int nLeft ) { if( nUnusedSticks = 0 and nLeft = 0 ) exit true; if( nLeft = 0 ) //一根刚刚拼完 nLeft := L; //开始拼新的一根 找一根长度不超过nLeft的木棒(假设长为len) 拼在当前棍子上,然后 exit Dfs(nUnusedSticks – 1, nLeft – len ); }
解题思路

首先确定搜索顺序
依然是从大到小搜索,因为小的灵活性较 高

放置蛋糕时遵从从上到下,从左到右的原 则
难点


本题的难点不在于如何找到搜索策略 难点是如何记录当前的状态 最简单的方法是将整个盒子分割成1*1的小 块分别记录是否被占据 但是,这必然是会超时的
按列记录


我们定义一个数组col[] 记录当前列 从上到 下一共连续放了多少的蛋糕 例如在第2~4列放入了一个size=3的小蛋糕, 那么inc(col[2],3), inc(col[3],3), inc(col[4],3)
剪枝1

为什么替换第i根棍子的第一根木棒是没用的?
因为假设替换后能全部拼成功,那么这被换下来 的第一根木棒,必然会出现在以后拼好的某根棍 子k中。那么我们原先拼第i根棍子时, 就可以用和 棍子k同样的构成法来拼,照这种构成法拼好第i 根棍子,继续下去最终也应该能够全部拼成功。

剪枝2

不要希望通过仅仅替换已拼好棍子的最后一根木 棒就能够改变失败的局面。
解题思路

初始状态:有N节木棒 最终状态:这N节木棒恰好被拼接成若干根等长 的棍子(裁前的东西称为棍子)

注意:棍子长度未知

枚举什么? 枚举所有有可能的棍子长度。 从最长的那根木棒的长度一直枚举到木棒长度 总和的一半。 对每个假设的棍子长度试试看能否拼齐所有棍 子:枚举长度是否可以整除棍子总长。

输入输出



输入数据 由多个案例组成,每个案例包括两行。第一行是一个不超过64的 整数,表示裁截之后共有多少节木棒。第二行是经过裁截后,所 得到的各节木棒的长度。在最后一个案例之后,是零。 输出要求 为每个案例,分别输出木棒的可能最小长度,每个案例占一行。
输入样例
9 521521521 4 1234 0 输出样例 6 5
相关文档
最新文档