目录
基础搜索算法 (Basic search algorithm)
复杂度玄学算法 (Uncertainty of Time Complexity)
正确性玄学算法 (Uncertainty of Correctness)
基础搜索算法
前言:此类算法一般是用来水部分分的。或者就是用来辅助一些算法。或者就是巧妙地利用题目性质做题,总之,很好用。
百度优先搜索
上百度找题解,可以解决大部分题目。
深度优先搜索
就是对于一个搜索路径,一直深入搜索下去,直到不能为止。
迭代加深搜索
就是在深搜的基础上加上一个深度限制,比如搜索深度到200就停止。
时间复杂度与深搜差不多。
折半搜索
把搜索的限制变成原来的一半。
比如n=16,我们搜索8个,然后后面的就边搜索边用hash来判断重复(是否有答案)。
宽度优先搜索
用队列实现,每个节点所展开的节点存到队列里,层层递进,搜索优先度与到起点的距离有关。
双向宽搜
对于一个起点状态与终点状态,两边同时宽搜(终点的拓展方法相反)。然后就时时刻刻用hash来判断是否相交。
时间复杂度:
单向:k^d(d为深度,k为每次拓展的状态的个数)
双向:sqrt(k^d)
例题:
T0:八数码
注,此题可以用各种方法做。
T1:[CQOI2013]新数独
给定一个空数独,现在要往其内填数字满足:
每行都是 1, … , 9 的排列
每列都是 1, … , 9 的排列
每个 3 × 3 的子矩阵都是 1, … , 9 的排列
每个 3 × 3 的子矩阵中相邻的两格要满足规定的大小关系
题解:
深搜直接填数,然后加剪枝。当然,优先剪掉第4个条件不符的,这样子更快。
T2:No name
给定数集合S,从中选出6个数a,b,c,d,e,f
求是否满足(a*b+c)/d-e=f
|S|<=100
题解:我们化化式子——
a*b+c=f*d+e*d
然后我们折半搜索,搜3个数,然后再搜剩下的3个数。加加剪枝即可。
时间复杂度O(|S|^3)
T3:平衡的子集(JZOJ 4841)
N个数中选出若干个数,分成两部分使得两部分的数的和相同。求方案。
N<=20;a[i]<=10000000000;
题解:折半搜索
每次搜索10个数,有3种状态—— -1(选到第一组),0(不选),1(选到第二组)
T4:[SDOI2011]打地鼠
有一个n*m的地图,每个点上有若干个地鼠。
你可以用一个大小为R*C的锤子打地鼠,每次会把一个大小为R*C区域内的每个点的地鼠个数减一,要求每次打的区域中每个点上都至少有一个地鼠。
你可以随意设置R,C,问最终最少打多少次。
n,m<=100,每个点的地鼠个数<=100000
题解:
直接枚举锤子的大小,然后判断大小是不是总数的约数。
判断可不可以砸就直接从左上角开始依次往后,能砸就砸。
复杂度玄学算法
前言:此类题的时间复杂度都很难证明或是有一个十分准确的值,一般就是O(能够)这种时间复杂度。要用到很多巧妙的方法去做,卡卡时间。当然,要看你非洲还是欧洲啦。
A*
A*主要在于一个估价函数,设为h(s),其中s是个状态。
令f(s)=g(s)+h(s)
其中g(s)表示从起点到当前状态的代价。
搜索时按照f(s)从小到大搜索。
可以说是赋予计算机一个智慧。
一个经典的比方——
从a走到b。
我们的估价函数就可以设为:
a与b的|横坐标差|+|竖坐标差|
当然,g(s)=a到当前状态s所在的位置走的路程。
然后,就可以按照f(s)来进行搜索。
具体的估价函数如何弄——
考虑对运行的效率和正确性有什么影响。
令h*(x)表示x到终点的最小代价。
当h(x) < h*(x)的时候会使得答案错误。
h(x)与h*(x)越接近,效率越高。
注意该问题即可。
IDA*
这个就是迭代加深版的A*。
加上最优性剪枝即可优化很多。
例题:
T0:八数码。
不多说。
T1:No name
给出n个点,m条边,要求从1到n的k短路。
n<=1000
题解:
A*做:
每次寻找f(x)最小的转移。
那么我们发现,从1出发,第K次到达n时就找到了第k短路。
估价函数就是:当前状态的点到终点的最短路。
T2:The Morning after Halloween
w×h的网格上有n小写字母(代表鬼)。要求把他们分别移动到相应的大写字母里。每步可以有多个鬼同时移动,但每步结束后不能有两个鬼在同一格,也不能在一步之内交换位置。
w,h≤16;n≤3
数据保证所有空格连通,所有障碍也连通。
且任意2×2的子网格中必然有一个障碍。
Time Limit: 6s
→
上面有四种走法。
题解:
解1:bfs。但是直接不行,因为状态数可能达到256^3
优化一:压缩状态,将每一个位置转换成[0,255]的整数来表示。
优化二:数据保证每个2×2的子网格至少有一个障碍,因此很多位置可转移的新位置是有限的。我们可以预处理每一个位置能转移到的新位置,从而降低转移的复杂度。
优化三:优化判重方法。最多只有3个鬼,所以可以用一个三维数组记录。
优化四:双向。
解2:A*。很显然可以做,但是我们看看如何设估价函数。
和K短路的思路类似,每次我们扩展一个估价最小的点。
关于h(n)估价函数的选取,大致有一下两种:
1.比较当前状态与目标状态有多少个点在正确位置上。
2.各点到目标位置的最大曼哈顿距离。
这是最常见的两种估价函数。这题显然应该是第二种。
正确性玄学算法
前言:水分、碾正解的利器。
爬山算法
简单的贪心。比如当前一个人要下山,那么他就每次选择一个比当前更低的地方走过去,否则就原地不动。
然而,很容易陷入坑中。
模拟退火
物理学知识用在信息学上面。
喜闻乐见。
根据分子热力学,在温度为T的时候:
p(dE)=exp(dE/(kT))
k是一个常数,dE为出现能量差的概率。
那么我们可以发现,温度会随着时间的变化去变化。
那些其实都不需要去管。
模拟退火其实就是另外的一种贪心,基于爬山算法。
形象比喻:我们就每次下山的时候,一开始活力充沛,就会有心情继续上山。但到后来,可能没精力了,那么渐渐地,心情不允许我们向上爬了。
也就是我们有一定几率会接受比当前劣一点的状态,但逐渐到后来,就不会有那么高的几率接受了。
这样往往可以以特别高的几率走到最优解。
遗传算法
生物学知识用在信息学上。
我还不会。
例题:
T1:费马点
一个图上有n个点,找一个点使这个点到其他点距离最短。
题解:模拟退火。
我们一开始有一个几率,在一个相对于中心的点(自己找)。然后我们就每次随机走一段一定的距离,最后就可以走到最优的答案。
T2:[HDU 5017] Ellipsoid
给定一个椭球,要求在上面找到一个点离原点最近。
题解:模拟退火。
与上题很像。
T3:[BZOJ 3680]吊打XXX
PTY又AK了。众人非常不爽,决定吊打PTY。
PTY将自己分身成n个,于是众人吊打n个PTY,方式如下:
用绳子把n个PTY吊起来,穿过天花板上一个坐标为(xi,yi)的孔,然后在上面绑在一起。
众人发现每个PTY的重量不一样,所以最终在的位置不是正中心。
问最终绑的那个绳结会到哪个位置。
n<=10000,-100000<=xi,yi<=100000
简单题意:一个圆盘,中间有一些线串过,线上方全部打了个结,下方有不同重量的球挂着。求这个结最终会到什么位置。
题解:模拟退火,我们每次同样地移动。
但是如何判断优与劣呢?
由于我们要使合力为0,那么我们就可以把不同的洞到结的距离依次记录,然后一个力可以分解成两个力。那么我们可以看做是坐标轴,那么我们就有4个力。分别计算即可。