【学习笔记】搜索与枚举

1.启发式搜索(A*)

对于一个搜索状态 \(x\),令 \(h(x)\) 为它到实际答案的步数,我们给它一个估价 \(f(x)=g(x)+H(x)\)。其中 \(g(x)\) 为搜到当前状态的步数,\(H(x)\) 为这个状态到目标状态的预估步数。

如果预估函数写得好能够在很短的时间内得到解。但是要保证 \(H(x)\le h(x)\)

流程就是搞成一个优先队列然后每次把 \(f(x)\) 最小的点拿出来扩展。

第一个扩展出来的一定是最优解。

证明:

令现在出来的解是 \(x\),它是由 \(z\) 扩展出来的,那么 \(H(z)=h(z)\)。因为只剩一条路只要你的预估函数有一点智商都会走这个,所以此时的 \(f(z)\) 是真实值。

也就是说走到 \(x\) 之前的 \(f(z)\) 全部是真实值,所以我们出来的第一个解就是最优解。

2.迭代加深

不考虑空间的情况下不如广搜。

考虑广搜的实质是空间换时间,dfs 的劣势在可能答案很近但是直接跑开了。

所以我们限制 dfs 层数 \(d\),传东西的时候传 \(d\) 下去,超出限制直接返回。搜到解退出,不然 \(d+1\) 再搜。

可以发现会有很多重复的搜索,但是理性考虑一下,我们每一次拓展至少要拓宽两倍,那么我们重复多搜一次也没有太大的关系。

相比于 bfs 优点在于空间需求小,而且 不需要保存状态

3.常见的搜索枚举

  • 子集枚举

普通子集枚举是 \(2^n\) 的,然后枚举自己内子集(就是对于每个枚举出来的子集 \(S\) 枚举它的子集)可以做到 \(3^n\)。不会证,但是大概不需要证。

for(int S=0;S<(1<<n);S++)for(int T=S;T;T&=(T-1))do sth;

不记得是不是这个了。

posted @ 2024-02-01 09:44  Wind_Leaves_ShaDow  阅读(10)  评论(0编辑  收藏  举报