在做题过程中我记下了如下的注意事项。
1. 对于在限制条件下的最优化问题,时间上优化的突破口也在限制条件。
eg 给n条边,从中选3条拼成一个三角形,要求周长最大的三角形
搜索时各种剪枝策略
2. 为了设计算法,
灵活的想象力(!!!)
算法的基础知识
也是必不可少的。
3. 对于标准库已经实现了的函数,尽量调用库函数,不要自己手写。但是,自己一定要清楚如果要自己写,需要怎么写(binary_search)。同时有的函数库(strstr)实现效率很低,所以还是需要自己手写。
4. 对数据合理的组织(排序,堆),是优化时间的常用方法,也是我们设计数据结构最重要的因素之一。
eg 因为多次查找的需要,我们才对一个字典进行排序,这样每次查起来就快很多。如果只用查一次,那我就没有必要对字典排序了。
5. 利用已经计算过的结果,是优化时间的最常用思想。
eg dp,记忆化搜索,打表,都是用空间换时间
6. 凡是可以用状态表示,有状态转移的问题,都可以转化为图的问题。
7. 搜索算法和动态规划算法,都是在多种策略中选取最优解,而贪心算法则不同,它遵循某种规则,不断的选取当前最优策略。
8. 竞赛中,常常需要证明自己对问题的设想是否成立。当时间紧迫又缺少证明思路时,建议至少测试一些数据来验证。另外,有些规律虽然对一般情况成立,却不能很好处理一些边界情况。(即使找到了规律,也不要就此大意,最好充分考虑一下是否有特殊情况或反例)
9. 二分搜索不只是查找,还可用于最优解问题。假设结果为x(这样就多了一个条件),然后二分这个x,这样就把最优化问题转化为了判定问题。(有些问题做优化可能不知道如何下手,但转成判定问题就很简单了)
eg “求满足某一条件的C(x)的最小(最大)x”这一问题,只要C(x)随x单调变化,那就可以用二分搜索。
10.二分搜索的结束判定,在输出小数的问题中,最好用循环次数作为终止条件。100次循环就可以达到10^-30的精度范围,基本上没有问题。
11. 最大(最小)化平均值问题,这种问题通常和二分搜索结合,利用∑Vi/∑Wi >= x,变形得到∑(Vi - x*Wi) >= 0,然后利用这个新条件。
12. 有些题目其实是找规律的题目,不要被题目复杂的条件,和很大的数据范围(往往也说明了这些题是有规律的)吓到。可以先从小规模样例入手,还可以先解决去掉一个限制条件的问题,通过这个思路再解决原问题。
13. 除了暴力外,拿到一个问题,把大问题化成小问题解决,也是常见的第一思路。
14. 对于需要快速得到数组中某一连续段的和(乘积,抑或等),都可以采用,先预处理出从第一个数到第i个数的sum值,存放在数组sum[] 中,然后第i到第j段值就是
sum(i~j) = sum[j] - sum[i-1]
(product(i~j) = product[j] /product[i-1])
(or(i~j) = or[j] ^ or[i-1])
15. 写程序时用到运算符需要考虑的一些问题
(1) 一旦做乘法和加法(尤其乘法),就要考虑到会不会有整数溢出的现象,要用32位整数还是64位还是大整数
(2)一旦在有取模的运算中,做减法一定要考虑会不会出现负数,负数取模在不同的语言中结果是不一样的,所以最好的做法是加特判。
(3)一旦有除法的运算,一定要考虑除数是否为0,有的话就要写特判。