搜索
DFS
最常用的搜索算法,一般用递归实现。
BFS
状态空间中的BFS搜索,和图上的BFS很类似,都可以用队列来实现。
伪代码:
bfs(s) {
q = new queue()
q.push(s), visited[s] = true
while (!q.empty()) {
u = q.pop()
for each edge(u, v) {
if (!visited[v]) {
q.push(v)
visited[v] = true
}
}
}
}
二分搜索
这个也简单,非常常用。
int binary_search(int start, int end, int key) {
int ret = -1; // 未搜索到数据返回-1下标
int mid;
while (start <= end) {
mid = start + ((end - start) >> 1); // 直接平均可能会溢出,所以用这个算法
if (arr[mid] < key)
start = mid + 1;
else if (arr[mid] > key)
end = mid - 1;
else { // 最后检测相等是因为多数搜索情况不是大于就是小于
ret = mid;
break;
}
}
return ret; // 单一出口
}
Meeting in the middle
对于规模较小,但暴力又差一点的问题(一个特征是某些测试便刚好N为最大规模的一半),有时可以用这个优化办法。主要思想是将整个搜索过程分成两半,分别搜索,最后将两半的结果合并。
习题
模拟
模拟就是用程序来模拟题目中发生的操作。
模拟题的特点是虽然算法没有难度,但往往代码量大,逻辑复杂,因此容易出错(这点上和实际的应用程序是比较像的)。有一些方法可以提高正确率:
- 多多手工模拟,保证对题义和corner case理解全面。
- 模块化、函数化,将公用的概念和操作提取出来。
- 分步骤、分模块测试。
- 要找到关键的点,或者不变量(invariants),往往可以简化问题。
习题
- P8188 Email Filtering S (USACO Feb 2022) - 关键间是最上方的folder决定了email一定需要滚动到哪里。
搜索与模拟习题
- T190986 [NOIP2004 普及组] 火星人 普及/提高-
- T191059【深基9.例4】求第 k 小的数 普及/提高-
- T191061 [JLOI2011]不重复数字 普及+/提高
- T191062【深基15.例2】寄包柜 普及-
- T191596 [NOIP2008 普及组] 立体图 普及/提高-
- T191599 绘制二叉树 普及+/提高
- [T191598 NOIP2017 提高组 时间复杂度 普及+/提高
- T191600 [NOIP2002 提高组] 字串变换 普及+/提高
- T191601 [USACO08FEB]Meteor Shower S 普及/提高-
- T191602 数独 普及/提高-
- T191603 [NOIP2011 提高组] Mayan 游戏 提高+/省选-
- T191605 [NOIP2018 提高组] 旅行 提高+/省选-
- T191606 [BalticOI 2011 Day1]Switch the Lamp On 提高+/省选-
- T198834 魔板 提高+/省选-