课程大纲
一、算法的基本概念
1.1 算法的基本概念、算法和问题
算法
:一个定义良好的计算过程
,它以某个值或一组值为输入
,并产生某个值或一组值为输出
计算问题
一般指明输入和输出的关系。
问题的实例
由计算该问题的解决方案所需的输入
组成
如果一个算法在每个输入实例中都得到正确的输出,那么它就是正确的。我们说一个正确的算法解决了给定的计算问题
。
设计算法(以插入排序为例):
(1)问题的形式化
(2)算法(伪代码、设计)
(3)分析
· 正确性
· 效率
涉及了一个计算模型–图灵机
DTM——确定性图灵机
作用:确定一个整数的奇偶性
机器实现过程:
· 配置:
sy—偶数; sn—奇数
运行时间:步数
内存:利用的磁带单元数
另一个计算模型例子——RAM
随机存取器
单处理器:指令一个接一个地执行;没有并发
原始操作:
- 算术运算(加、减、乘、除、取余、取整)
- 数据移动(load、copy、stroe)
- 控制(有条件/无条件地分支、子程序调用和返回)
每条这样的指令花费的时间是固定
的
运行时间:原始操作的数量–可以看作一个函数的输入个数n
空间:利用的内存单元数
1.2 对算的衡量–时空复杂性
以排序算法为例:
最好情况:tj = 1
最坏情况:tj = j
1.3 函数的增长–渐进符号
O
O
O——渐进上界
性质:
- 自反性—— f = O ( f ) f = O(f) f=O(f)
- 乘积—— f 1 = O ( g 1 ) , f 2 = O ( g 2 ) → f 1 f 2 = O ( g 1 g 2 ) f_1=O(g_1),f_2=O(g_2)\rightarrow f_1f_2 = O(g_1g_2) f1=O(g1),f2=O(g2)→f1f2=O(g1g2)
- 和—— f 1 = O ( g 1 ) , f 2 = O ( g 2 ) → f 1 + f 2 = O ( m a x { g 1 , g 2 } ) f_1=O(g_1),f_2=O(g_2)\rightarrow f_1+f_2 = O(max \{g_1,g_2\} ) f1=O(g1),f2=O(g2)→f1+f2=O(max{g1,g2})
- 传递性—— f = O ( g ) , g = O ( h ) → f = O ( h ) f=O(g),g=O(h)\rightarrow f=O(h) f=O(g),g=O(h)→f=O(h)
Ω
\Omega
Ω——渐进下界
Θ
\Theta
Θ——渐进紧确界
o
o
o——非紧确上界
ω
\omega
ω——非紧确下界
二、分治法
2.1 分治法的基本思想–归并排序
分治法:
- divide–将问题分成几个同类的子问题
- solve–递归地解决子问题
- combine–将子问题的解决方案组合成整体解决方案
以归并排序为例:
-
将数组分成两部分
-
分别为两部分排序
-
最后将已排序的数组合并
分析时间复杂度:
得到递归式:
如何求解递归式?- 代入法
- 递归树法
- 主方法
- 代入法
提出假设——>验证假设、求解常数
2.递归树
3. 主方法
2.2 最大子数组问题
三种可能情况:
分治法:
很容易能够得到递归式:
三、动态规划
动态规划(Dynamic Programming)与分而治之(divide-and-conquer):通过组合子问题
的解来求解原问题。
1、分治法:互不相交的子问题,递归地求解子问题。如果子问题有重叠,则递归求解中就会反复地求解这些公共子问题,造成算法效率的下降。
2、动态规划:有子问题重叠的情况,即不同的子问题具有公共的子子问题。动态规划算法对每个这样的子子问题只求解一次,将其解保存在一个表格中,再次碰到时,无需重新计算,只从表中找到上次计算的结果加以引用即可。
最优化问题(optimization problems):这一类问题的可行解可能有很多个。每个解都有一个值,我们希望寻找具有最优值的解(最小值或最大值)。
注:这里,我们称这个解为问题的一个最优解(an optimal solution),而不是the optimal solution,因为最优解也可能有多个。
动态规划算法的步骤:
- 刻画一个最优解的结构特征;
- 递归地定义最优解的值;
- 计算最优解的值,通常采用自底向上的方法;
- 利用计算出的信息,构造一个最优解。
3.1 钢条切割、矩阵乘法–动态规划设计方法
一、钢条切割:
给定一段长度为n英寸的钢条和一个价格表P,求切割钢条方案,使得销售收益 rn 最大。
如果长度为n英寸的钢条的价格pn足够大,则可能完全不需要切割,出售整条钢条是最好的收益。
递归求解:
动态规划:
子问题图
:
重构解——以给出切割方案
:
二、矩阵链乘法
构造最优解:
3.2 动态规划原理、设计和分析动态规划算法
如何设计DP算法:
(1)最优子结构
“剪切-粘贴”(cut-and-paste)技术
:
一般用反证法证明:假定子问题的解不是其自身的最优解,而存在“更优的解” ,那么我们可以从原问题的解中“剪切”掉这些“最优解”的部分,而将“更优的解”粘贴进去,从而得到原问题的一个“更优”解,这与最初的解是原问题最优解的前提假设相矛盾。因此,不可能存在“更优的解”。反之,原问题的子问题的解应是其自身的最优解——最优子结构性成立。
(2)状态转移方程
(3)最优解的构造
DP满足两个要素:
- 具备最优子结构
- 子问题重叠
DP算法时间:
求原问题最优解的代价通常就是子问题最优解的代价再加上由此次选择直接产生的代价。
3.3 最长公共子序列
递推式
四、贪心算法
贪心算法
是这样一种方法,分步骤实施,它在每一步仅作出当时看起来最佳的选择,即局部最优的选择,希望这样的选择能导致全局最优解。
经典问题:最小生成树问题的Prim算法(加点法)、Cruskal算法(加边法),单源最短路径Dijkstra算法等,以及一些近似算法。
4.1 活动选择问题
证明:
4.2 贪心算法原理、设计和分析
贪心求解的一般步骤:
- 确定问题的最优子结构;
- 每次对其作出一次选择;
- 证明作出贪心选择后,原问题总是存在最优解,即安全;
- 证明作出贪心选择后,剩余的子问题满足:其最优解与贪心选择组合即可得到原问题的最优解。
贪心算法中贪心选择性质和最优子结构性是两个关键要素:
- 贪心选择性质:可以通过做出局部最优(贪心)选择来构造全局最优解。
如何证明?
通常先考查某个子问题的最优解,然后用贪心选择替换某个其它选择来修改此解,从而得到一个相似但更小的子问题。 - 最优子结构性
0-1背包问题:
贪心算法:
动态规划:
4.3 Dijkstra最短路算法
证明正确性:
五、最短路问题
最优子结构:
三角不等式:
上界性质:
无路径性质:
收敛性质:
路径松弛性质:
证明
G
π
G_\pi
Gπ是最短路径树:
首先证明引理——前驱子图形成以源点为根的有根树
前趋子图性质:
无负环:
简单路径:
动态规划寻找最短路:
检测负环:
5.1 Bellman-Ford算法
证明正确性:
DAG算法的正确性:
5.2 基于矩阵乘法的动态规划算法
从边数入手:
5.3 Floyd-Warshall算法
从结点入手:
六、最大流问题
6.1 流网络的基本概念
6.2 Fold-Fulkerson算法
最后的残差网络中,源点s能够到达的结点集合——最小割
最小割的值=最大流流量
流与切割之间的关系
弱对偶性:
最大流最小割:
增广路径定理:
6.3 最大匹配问题
七、NP完全性
7.1 了解P和NP的基本概念
7.2 归约和NP完全性
归约:
证明是个NPC问题:
7.3 NP完全问题举例
主要是团问题、定点覆盖问题、子集和问题
哈密顿回路的证明不用掌握(先别看了)
3
−
S
A
T
−
C
N
F
≤
p
C
l
i
q
u
e
3-SAT-CNF\le_p Clique
3−SAT−CNF≤pClique
C
L
I
Q
U
E
≤
p
V
e
r
t
e
x
C
O
V
E
R
CLIQUE\le_p Vertex COVER
CLIQUE≤pVertexCOVER
证明集合覆盖是NPC问题:
八、近似算法
*8.1 顶点覆盖问题的近似算法
证明:
8.2 度量TSP问题的算法和一般TSP问题的不可近似性
三角不等式:
证明:
不满足三角不等式:
T T