一开始只是抱着开阔视野的心态来的,想着算法是IT行业哪里都会用到的东西,学完之后觉得卜老师不愧是教了13年的老师,很多地方都很受益,虽然不是专门做算法的,其中的很多思想都对以后的工作有一定启发。
观察问题的角度
问题的可分解性
想要解决一个复杂的问题,我们首先从这个问题最简单的实例入手,这个最简单的实例能用什么方法解决?复杂的问题能不能分解成简单的问题?
可行性解的形式以及解之间的变换关系
问题的可行解的形式是什么?可行解的总数有多少?可行解能否一步一步的逐步构建出来?我们能否对一个可行解施加小幅度的扰动,将它变成另外一个可行解?
类似的问题
和给定的问题类似的问题有哪些?解决类似问题的算法能够直接运用于解决当前的问题?如果不能,那么是什么因素造成了妨碍?能否想到方法消除这些妨碍的因素?
现有算法的不足
现有的算法有哪些不足?比如:是否存在冗余计算?如果存在的话,能否想到办法消除冗余?
解决问题的思路
基于对问题结构观察的算法设计
在解决一个问题的时候,需要分析这个问题是怎么组成的,能够怎么抽象。而不是直接一个一个算法去套,这种硬套的方法就是碰运气,如果运气好就能用,运气不好就不行了。
从最简单的例子做起
做复杂的问题很多时候会很懵逼,这个时候就需要从最简单的情况考虑问题比如n=2,n=3的时候,这样会更加容易上手。
试图把大问题分解成小问题
如果从简单问题的观察中,发现问题是可以分解的,那么我们可以尝试把大问题分解成小问题。
试图从粗糙开始逐步改善
如果从简单问题的观察中,发现问题是不能分解的,那么就从最笨最简陋的方法开始逐步优化。
试图枚举所有的解,但是要用聪明的方法
如果问题的解是一种集合,那么可以尝试枚举所有的解。在遍历的过程中要学会剪枝,不要暴力检索。
难以优化的函数使用下界或者上界函数代替
例如:EM,Lagrangian,log barrier
$$
\large \begin{matrix}
min & f(x)\
s.t. & h(x) \geq 0
\end{matrix}
$$
$f(x)$难以计算的时候,使用拉格朗日乘子,$L(x,\lambda)=f(x)-\lambda h(x)$,如果$\lambda \geq 0$那么必有$f(x) \geq L(x,\lambda)$。
复杂操作的潜力一定要挖掘干净
例如:Dinic’s algorithm
一次BFS需要O(m)的时间,只用于增广一条s->t
路。而把一条路改成所有路就能最大程度的增加效率。(这个算法其实我没听懂23333)
求同时满足多个条件的解,分步满足,并利用对称性
在我们解决LP问题的时候,通常需要满足多个条件,那么我们可以这样来解决问题,先满足其中的大部分条件,然后再循环逼近另外的条件,或者降低不满足其他条件的程度。
想想对偶
依旧是在解决LP问题时候的一种策略,如果单纯的替换变量不好做,那么可以试试对偶来解决问题。
Random sampling
分治思想中的快排,在选取切分点的时候不会去选择最优的pivot而是随机选择一个。
Scaling number
在有很多数字计算的问题中,可以采用放缩的方法降低计算量。比如所有的数字都除一个数,如果数字小于1就变成0。
从最好 => 足够好
这个思想和random sampling有点类似,不一定要最好的分支点(命中概率$\frac{1}{n}$),只要足够好就行(命中概率$\frac{1}{2}$),如果要对快排再次改进,就可以让选择pivot的时候限制在一个较好的区间中,避免pivot在最边上的情况。
最后
推荐了两本书Polya的《怎样解题》和费曼的《物理学讲义》。一本书是对解题思维过程的理解,另外一本书是著名的物理学家费曼的物理讲义,想要了解什么书才是好书,把科学的概念和生活联系在一起,而不是枯燥的阐述和推理。