搜索
搜索
有一个lq暴论:会搜索就能拿省一。其实也没什么问题,但是搜索掌握的太差了,目前还是只会回溯法和一点点的迭代加深。
回溯
这个是搜索最基本的操作了,应该不需要赘述。
折半搜索
当一个搜索树的深度足够深,我们就会花上 \(dep\) 的指数级代价。
但是当我们的始末态明确的时候,我们可以从头开始搜一半的深度,从尾开始搜一半的深度,如果两种能够拼接在一起,就说明这是一种合理的解法。
例题
- P4799
- CSP2022T1
这两道例题里面的折半拼接方法大概是,把每一半可能的答案都分别存进数组里面,然后用大概类似于双指针或者是二分的办法来贪心选取拼接之后的答案。
A*
一个甚至在竞赛之外也有很多应用的算法,比如MOBA类游戏中的寻路。
就是给状态设计一个估值函数,然后根据估值函数来对状态进行优劣排序,存在一个优先队列里面进行广搜。
这里摘一段 OI WIKI 的原文 :
定义起点 \(S\) ,终点 \(T\) ,从起点(初始状态)开始的距离函数 \(G(x)\) 到终点(最终状态)的距离函数 \(H(x)\) ,以及每个点的估价函数
\(f(x)=G(x)+H(x)\)
A * 算法每次从优先队列中取出一个 \(f\) 最小的元素,然后更新相邻的状态。
如果 \(H<H_{实际}\) ,则 A * 算法能找到最优解。(这是极其重要的一点) 这其实是意味着 在搜索的过程中不会错过最优解
当\(H=0\) 时,A * 算法变为 Dijkstra;当 \(H=0\) 并且边权为 \(1\) 时变为 BFS。
(因此可以通过BFS快速求简单边权为 \(1\) 的图的最短路)。
//TODO
迭代加深
顾名思义就是给搜索树限定一个深度。
void dfs(int x,int dep,int limit)
{
if(dep>limit)return;
else dfs(....);
}
int main()
{
for(int dep=1;dep<=n;++dep)
dfs(start,0,dep);
return 0;
}
这样的话就不至于一条路走到黑了,当然只有在答案足够小的时候才能够使用(或者说是数据范围足够小)
例题
- 埃及分数
IDA*
这个可以顾名思义一下,实际上就是把 A* 和 迭代加深 套在一起了。
有段时间非常喜欢写这个,但是缺点就在于有些重复的东西还是会搜很多次。
例题
- 埃及分数
Dancing Links
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/18566004

浙公网安备 33010602011771号