题目 | 成绩 | 评价 |
---|---|---|
T1 | 10 | 以为暴力能拿60分,结果只有十分 |
T2 | 0 | 翻车 |
T3 | 4 | 骗到4分 |
翻车翻到底了
搜索算法是利用计算机的高性能来有目的的穷举一个问题解空间的部分或所有的可能情况,从而求出问题的解的一种方法。现阶段一般有枚举算法、深度优先搜索、广度优先搜索、A* 算法、回溯算法、蒙特卡洛树搜索、散列函数等算法。在大规模实验环境中,通常通过在搜索前,根据条件降低搜索规模;根据问题的约束条件进行剪枝;利用搜索过程中的中间解,避免重复计算这几种方法进行优化。
dfs深度优先搜索和bfs广(宽)度优先搜索是搜索的两种基本模型。
例题1——斗地主
题目地址
luogu斗地主
luogu斗地主增强版
解:我们需要考虑预处理dp数组: dp[x][y][z][w] 表示分别有 x、y、z、w 种出现 4、3、2、1 次的牌,不出顺子最少几步打完。DFS 搜索打顺子的情况,结合 dp 计算答案。加上最优性剪枝就可以A掉。
中途相遇法指的是,从起点和答案两边同时开始搜索,在中间相遇并求解的方法。这种方法有什么好呢?我们用给一张图片来解决。
空白部分在中途相遇法中就可以忽略掉了。
例题2
已知 N 元高次方程:sum_{i<=N} k[i] * x[i] ^ p[i] = 0,设未知数均为不大于 M 的正整数,求解的个数。N <= 6, M <= 150。
解:将前半部分的搜索结果存入 Hash 表,再搜后半部分。这就是一个中途相遇法。
给定素数 M 和整数 A、B,解方程 A^x = B (mod M),给出任意一组解,或者说明无解。A, B <= M <= 10^9。
解:这道题目需要使用离散对数。什么是离散对数呢?
我们可以联系对数的概念,若A^x=B那么,x是B以A为底对数。同样的,在模意义下,A^x=B(mod m),x就是B以A为底,模m意义下的对数。
启发式搜索又称为有信息搜索,它是利用问题拥有的启发信息来引导搜索,达到减少搜索范围、降低问题复杂度的目的,这种利用启发信息的搜索过程称为启发式搜索。启发式搜索中应用最为广泛的搜索技巧当属 A* 和 IDA* 了,前者是 BFS 的启发式版本,后者是前者的迭代加深版本。
原理
A* 和 IDA* 算法中,对每一个状态 x 引入了一个估价函数f (x) = g(x) + h(x), 其中 g(x) 是目前状态的实际代价,而 h(x) 是 “目前状态到目标状态的估计代价”。在 A* 算法中,估价函数的作用是调整搜索顺序让最优的解最 先搜索到。而在 IDA* 中,估价函数作为最优性剪枝出现。 为了保证正确性,一般要求 h(x) <= 从 x 到目标状态的实际代价。特别地,当 h(x) = 0 时,A* 和 IDA* 分别退化为一般的BFS和迭代加深算法。
算法原理:
A*:
BFS 的改进,用优先队列维护所有可以扩展的状态
每次把期望里目标更近的状态拿出来扩展
IDA*:
从小到大“试答案”并进行判定
ans = 0; while (!check(ans)) ans++;
判定一般使用深搜(当 深度 > ans 就不必搜下去了)
优劣比较:
A*:容易理解,实现容易;空间需求巨大
IDA*:不太容易实现,空间需求小,但是有重复扩展问题
PS:因为一般搜索树第 x 层大小远大于 x-1 层,一般认为 IDA* 的在找到答案之前的重复扩展都“微不足道。
例题3——骑士精神
题目地址
luogu骑士精神
在一个 5 * 5 的棋盘上有 12 个白骑士和12 个黑骑士,每次可以选择一个骑士合法地走到空地,给定初始和目标状态,问最少走多少步能到达目标状态,(同种颜色的骑士是不互相区分的)。
小总结
从名字就可以看出,启发式搜索是一个比较玄学的东西,具体效果和估价函数有很大的关系,如果能判断一道题是玄学搜索,或者没有其它好办法的时候,不妨试一试。
一种强大的搜索算法,但是我们并不讲,有兴趣的同学自行查阅相关资料。
工具和方法
基础计数原理——加法、乘法原理(ex:减法、除法原理)
排列组合数及其公式、容斥大法
ex:线性递推数列、母函数方法
经典计数数列
Fibonacci、Catalan、Bell 数
错位排列数
满足的状态转移方程是:f(n
)=f(n-1)+f(n-2),边界条件是f(1)=1,f(2)=1;
例题4——数楼梯
题目地址:luogu数楼梯
解:我们可以考虑最后一级(第n级)们怎么越过去呢,很显然,我们要么同时越两级上去,要么只越一级上去。如果越两级,那么去掉这两级后,剩下n-2级楼梯就是一个规模更小的子问题了;如果越一级,那么去掉这一级后,剩下n-1级楼梯就是一个规模跟小的子问题了,根据加法原理,我们最后n级楼梯的解就是两个规模分别为n-1和n-2的子问题的答案之和。f(n)=f(n-1)+f(n-2);就是一个斐波那契数列。
卡特兰数应当满足下面的关系:
卡特兰数满足递推式:
h(n)= h(0)* h(n-1)+h(1)*h(n-2) + … + h(n-1) *h(0) (n>=2)
或者满足
h(n)=h(n-1)*(4 *n-2)/(n+1);
而且满足
h(n)=C(2n,n)/(n+1) (n=0,1,2,…)
也就是满足
h(n)=c(2n,n)-c(2n,n-1)n=0,1,2,…)
例题5——栈
题目地址
luogu栈
解:我们这道题目需要枚举的是每一元素出栈的顺序,对于第一个点,如果它是第一个出栈的,那么它之前就会有0个元素出栈,这个是一个规模为0的子问题,记作f(0),然后,它之后会有n-1个元素出栈,这是一个规模为n-1的子问题,记作f(n-1),根据乘法原理,当第一个点是第一个出栈的时候,方案数为f(n-1)*f(0);同样的,我们继续枚举,如果第一个点是第二个出栈的,那么它之前的点有1个,出栈的方案数是f(1),在它之后有n-2个点,出栈的方案数是f(n-2),根据乘法原理,f(n-2) *f(1)…………我们发现这是一个卡特兰数。
满足:s(n + 1, k) = s(n, k - 1) + n * s(n, k)
S(n,0) = 0,
S(1,1) = 1.
边界条件: S(0 , 0) = 1 S(p , 0) = 0 p>=1 S(p , p) =1 p>=0
一些性质: S(p ,1) = 1 p>=1 S(p, 2) = 2^(p-1)– 1 p>=2
经典模型:包含n个元素的集合分作k个环排列的方法数目
满足:s(n + 1, k) = s(n, k - 1) + k * s(n, k)
S(n,k)=0; (n
Bn是基数为n的集合划分数目。集合S的一个划分是定义为S的两两不相交的非空子集的族,它们的并是S。
bell的递推公式:
而且适合Dobinski
也是适合Touchard同余:
若p是任意质数,则会有
每个bell数都是第二类斯特林数的和
今天主要讲了搜索入门和简单计数。搜索入门中A*和IDA *要重新去学习一下,简单计数中的一些公式要再记忆一下。