按照方式划分,算法一般分为以下几种:
贪心算法 (Greedy Algorithm)
在每一步选择中都采取当前状态下最优,从而希望结果是全局最优的算法策略。
缺点: 不能保证对所有问题都能得到全局最优解
适用场景: 满足贪心选择性质(无需关注当下选择对未来影响,也不需要回头修改)、最优子结构()
活动选择问题、哈夫曼编码、最小生成树(Prim/Kruskal算法)以及找零钱问题(特定面额下)。
分治(Divide and Conquer)
"分而治之"。它将一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解。原问题的解即子问题的解的合并。
适用场景:子问题之间相互独立。
快速排序、归并排序、二分查找、大整数乘法。
动态规划(Dynamic Programming, DP)
动态规划是一种将复杂问题分解成若干个相互联系的子问题,通过求解子问题并保存其结果(避免重复计算),从而得到原问题最优解的方法。
适用场景: 求最大值/最小值、方案数等。
典型应用包括0/1背包问题、最长公共子序列、最短路径(如Floyd算法)、斐波那契数列优化。
回溯(Backtracking)
"回溯算法是一种通过深度优先搜索策略
约束剪枝:剪除路径中违反规则的分支。
适用场景: 需要找出所有解或任意解的问题。
典型应用包括八皇后问题、全排列、数独、图的着色问题。
分支限界
通常采用广度优先或最小耗费/最大效益优先的方式搜索。通常用于求解最优化问题,通过"界限"函数来剪掉不可能产生最优解的分支,从而更高效地找到最优解。通常通过队列实现。
界限剪枝:如果这个界限比当前已经找到的最好解还要差,那么这个分支就会被直接丢弃
适用场景: 组合优化问题,特别是求最优解的场景。
旅行商问题、单源最短路径(Dijkstra算法可视为一种分支限界)、0/1背包问题(求最优解)。
启发式思想
对于实际问题的解决,我们一般需要基于经验或特定的规则制定策略。需要在合理的时间内,找到一个足够好 的可行解,而非最优解,其往往是时间与解质量的一个平衡。
主要解决NP难问题
元启发式算法
这是一类更高层次、更通用的策略框架。它们不依赖于具体问题,提供了一套指导方针,可以应用于各种各样的优化问题,通常具有更强的全局搜索能力和跳出局部最优的能力。
典型代表:
遗传算法 (GA):模拟生物进化过程(选择、交叉、变异)。
模拟退火 (SA):模拟金属冶炼中的退火过程,以一定概率接受"坏解"来跳出局部最优。
蚁群算法 (ACO):模拟蚂蚁通过信息素寻找路径的集体行为。
粒子群优化 (PSO):模拟鸟群或鱼群的社会行为。
A*算法
NP难问题(NP-hard problem)
这类问题是计算机科学中"最难"的一类问题,目前普遍认为不存在能在合理时间内找到精确解的通用算法。
NP类问题:指那些"求解困难,但验证容易"的问题。
NP完全问题:既是NP问题,也是NP难问题。它必须能被快速验证。
NP难问题:不一定是NP问题。它可能连"快速验证"都做不到,因此可能比NP完全问题更难。
一个问题是NP难的,所有NP类问题都可以在多项式时间内"归约"到这个问题。
这里的"归约"(Reduction)可以通俗理解为"转化"。如果问题A可以归约为问题B,就意味着:只要我能解决问题B,我就能用它来解决A。因此,问题B的难度至少和问题A一样高。
所以,NP难问题就是那些难度不低于任何NP问题的问题。它们是计算复杂性中的"天花板"。