算法2.0

This commit is contained in:
estomm
2020-01-05 14:59:34 +08:00
parent 69da6ff9de
commit d30e0fd00b
26 changed files with 716 additions and 28 deletions

View File

@@ -0,0 +1,19 @@
# 近似算法
## 1 近似算法
### 概念
不同的近似算法有各种各样的复杂度,但其中许多算法都是基于特定问题的直观推断贪婪算法。直观推断是一种来自于经验而不是来自于数学证明的常识性规则。如果我们使用的算法所给出的输出仅仅是实际最优解的一个逼近,我们就会想知道这个逼近有多精确。
### 近似算法精度
对于一个对某些函数 f 最小化的问题来说,可以用近似解的相对误差规模
$$
re(S_a)=\frac{f(S_*)}{f(S^a)}
$$
### 近似算法的性能
对于问题的所有实例它们可能的r(sa)的最佳也就是最低上界被称为该算法的性能比计作RA。
性能比是一个来指出近似算法质量的主要指标我们需要那些RA尽量接近1的近似算法。

View File

@@ -0,0 +1,23 @@
# 遗传算法
## 1 遗传算法概述
### 步骤
1. 随机产生一组初始个体构成初始种群并评价每一个体的适配值fitness value
2. 判断算法收敛准则是否满足。若满足则输出搜索结果;否则执行以下步骤。
3. 根据适配值大小以一定方式执行复制操作。
4. 按交叉概率pc执行交叉操作。
5. 按变异概率pm执行变异操作。
6. 返回步骤2。
### 遗传算法的特点
遗传算法利用生物遗传和进化的思想实现优化
* 对问题参数编码成“染色体”后进行进化操作,而不是针对参数,这使得它不受某些函数约束条件的限制,如连续性、可导性等;
* 搜索过程是从问题解的一个集合开始的,而不是从单个个体开始的,具有隐含并行搜索特性,从而大大减小了陷入局部极小的可能;
* 具有全局搜索能力;
* 适应性、收敛性。

View File

@@ -0,0 +1,9 @@
# 邻域结构优化算法
## 1 算法概述
### 算法原理
利用邻域结构进行逐步优化的局部搜索算法:
算法从一初始可行解 s 出发利用状态发生器持续地在s 的领域中搜索更好的解若能找到更优解则以其替代s 成为新的当前解,然后重复上述过程,直至终止条件满足。

View File

@@ -0,0 +1,58 @@
# 禁忌搜索算法
## 1 算法说明
### 算法概述
禁忌搜索TS是对局部邻域搜索的一种扩展是一种全局优化算法。TS算法通过引入一个禁忌表和相应的禁忌准则来避免局部迂回并通过“渴望准则”来挽救某些被禁忌的相对优化解进而保证全局的有效搜索以实现全局优化。
标记对应已搜索到的局部最优解的一些对象,并在进一步的迭代搜索中尽量避开这些对象,但不是绝对禁止循环,从而保证对不同的有效搜索途径的探索。
### 基本思想
* 给定一个当前解(初始解)和一种邻域结构,在当前解的邻域中确定若干候选解;
* 若最佳候选解对应的目标植优于 “best so far” 则忽视其禁忌特性用其替代当前解和“best so far”值并将相应的对象加入禁忌表同时修改禁忌表中各对象的禁忌任期
* 若不存在上述候选解,则选择在候选解中非禁忌的最佳状态为新的当前解,而无视它与当前解的优劣,同时将相应的对象加入禁忌表,并修改禁忌表中各对象的任期;
* 重复上述迭代搜索过程,直至满足停止条件。
### 算法原理
邻域
对于组合优化问题给定任意可行解xx∈DD是决策变量的定义域对于D上的一个映射Nx∈D→N(x)∈2(D) 其中2(D)表示D的所有子集组成的集合N(x)成为x的一个邻域y∈N(x)称为x的一个邻居。
候选集合
候选集合一般由邻域中的邻居组成,可以将某解的所有邻居作为候选集合,也可以通过最优提取,也可以随机提取,例如某一问题的初始解是[1,2,3],若通过两两交换法则生成候选集合,则可以是[1,3,2],[2,1,3],[3,2,1]中的一个或几个。
禁忌表
禁忌表包括禁忌对象和禁忌长度。由于在每次对当前解的搜索中,需要避免一些重复的步骤,因此将某些元素放入禁忌表中,这些元素在下次搜索时将不会被考虑,这些被禁止搜索的元素就是禁忌对象;
禁忌长度则是禁忌表所能接受的最多禁忌对象的数量,若设置的太多则可能会造成耗时较长或者算法停止,若太少则会造成重复搜索。
评价函数
用来评价当前解的好坏TSP问题中是总旅程距离。
特赦规则
禁忌搜索算法中,迭代的某一步会出现候选集的某一个元素被禁止搜索,但是若解禁该元素,则会使评价函数有所改善,因此我们需要设置一个特赦规则,当满足该条件时该元素从禁忌表中跳出。
终止规则
一般当两次迭代得到的局部最优解不再变化或者两次最优解的评价函数差别不大或者迭代n次之后停止迭代通常选择第三种方法。
### 算法流程
![](image/禁忌搜索算法.png)
1. 定义相邻结构和如下算法参数: ttTabu tenure、m (number of candidatesm > tt ;
2. 以某种方法产生初始解s置禁忌表为空
3. 从s的邻域中选取m 个 候选解;
4. 选取候选解中的最优解X
5. 若X不在禁忌表中则s=x, 将X存入禁忌表且置其当前禁忌值为tt, 将禁忌表中其它元素值(禁忌值)减 1然后将禁忌值为0的禁忌元素释放出禁忌表转到8
6. 若X在禁忌表中且X的目标函数值优于当前最优解best so far则s=x, 将X禁忌值置为tt, 将禁忌表中其它元素值(禁忌值)减 1然后将禁忌值为0的禁忌元素释放出禁忌表转到8
7. 若X在禁忌表中且X的目标函数值不优于当前最优解best so far则从候选解中取得下一X转到4
8. 判断算法终止条件是否满足若是则结束算法并输出优化结果否则转到3

View File

@@ -128,7 +128,8 @@ $$
> 注:对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。反之,数组中如果分布非常不均匀,那么插值查找未必是很合适的选择。
### 复杂度分析
查找成功或者失败的时间复杂度均为O(log2(log2n))。
查找成功或者失败的时间复杂度均为$O(log_2(log_2n))$
最差时间复杂度O(n)
### 代码实现
```

View File

@@ -219,4 +219,47 @@ RANDOMIZED-SELECT 的最坏运行时间为 Θ(n2),即使是要选择最小元
106
107 static Random random = new Random(new Guid().GetHashCode());
108 }
```
```
## 3 分治法选择最大最小值
### 问题描述
在一个整数组 A[1…n]中,同时寻找最大值和最小值。
### 算法原理
* 非递归算法
```
1 x ← A[1]; y ← A[1]
2. for i ← 2 to n
3. if A[i ] < x then x ← A[i ]
4. if A[i ] > y then y ← A[i ]
5. end for
6. return (x, y)
```
* 递归算法
1. 将数组分割成两半A [1… n/2] 和A [(n/2) +1… n]。(设 n 为2的幂
2. 在每一半中找到最大值和最小值,并返回这两个最小值中的最小值及这两个最大值中的最大值。
```
Procedure minmax (low, high)
if high low = 1 then
if A [low] < A [high] then return (A [low], A[high])
else return ( A[high], A [low])
end if
else
mid ←
(x1, y1) ← minmax (low, mid)
(x2, y2) ← minmax (mid + 1, high)
x ← min {x1, x2}
y ← max {y1, y2}
return (x, y)
end if
```
### 算法效率
O(n)
> 书上给的分治法是O(log n)我觉得不对

View File

@@ -4,7 +4,7 @@
### 基本思想
* 求解问题算法的复杂性一般都与问题规模相关,问题规模越小越容易处理。
* 分治法的基本思想是,将一个难以直接解决的大问题,分解为规模较小的相同子问题,直至这些子问题容易直接求解,并且可以利用这些子问题的解求出原问题的解。各个击破,分而治之。
* 分治法的基本思想是,将一个难以直接解决的大问题,分解为**规模较小**的**相同类型**的子问题,直至这些子问题容易直接求解,并且可以利用这些子问题的解求出原问题的解。各个击破,分而治之。
* 分治法产生的子问题一般是原问题的较小模式,这就为使用递归技术提供了方便。递归是分治法中最常用的技术。
![](image/分治法原理.png)
@@ -77,28 +77,182 @@ $$
T(n)=n^{\log_ba} +\sum_{i=2}^{\log_bn-1}a^jf(n/b^j)
$$
* 关系式说明
![](image/递归算法-等比收缩说明.png)
![](image/递归算法-时间复杂度.png)
$$
T(n)=O(n^{\log_ba})+O(f(n))\log_bn
$$
其真正的时间复杂度,由前后两部分决定。可以通过计算,得到较大部分的时间复杂度,为整体的时间复杂度。
* 当f(n)为常数时
$$
T(n)=\begin{cases}
O(n^{\log_ba}) & a\not = 1\\
O(\log n) & a=1
\end{cases}
$$
* 当f(n)=cn时
$$
T(n)=\begin{cases}
O(n)&a<b\\
O(n\log n)& a=b\\
O(n^{log_b^a})&a>b
\end{cases}
$$
### 递归算法理解
* 递归算法本质上是一种自顶向下的思考模式。即数学上所说的归纳法。有结果一步一步归纳,得到验证其条件的正确性。问题规模逐渐变小。
* 非递归算法的本质是一种自底向上的思考模式。即数学上所说的推导法。将一些零碎的部分逐渐求解,渐渐得到最终的结果。问题逐渐组装成目标问题。
在使用递归的时候,应该从顶层考虑怎么分割。在使用非递归算法的时候,应该考虑怎样从顶层进行组合。
## 0 减治法概述
### 基本思想
一个问题给定实例的解和同样问题较小实例的解之间的关系。一旦建立了这样一种关系,我们既可以递归地,也可以非递归地地来运用减治技术。
### 分类
* 减去一个常量 (decrease by a constant)
* 减去一个常数因子(decrease by a constant factor)
* 减去的规模是可变的(variable size decrease)
### 算法原理
* 在减常量变种中每次算法迭代总是从实例规模中减去一个规模相同的常量。经常地这个常量等于一。函数f(n) = an可以用一递归定义来计算
```
f(n) = f (n-1) *a 如果n > 1
= a 如果n = 1
```
* 减常因子技术意味着在算法的每次迭代中总是从实例的规模中减去一个相同的常数因子。在多数应用中这样的常数因子等于二。例如计算an的值是规模为n的实例an = (an/2)2。O(log n);
* 在减治法的减可变规模变种中算法在每次迭代时规模减小的模式都是不同的。例如欧几里得算法gcd (m,n) = gcd (n, m mod n)
### 算法效率
与蛮力法相同。但是思想不同。
### 与分治法对比
该算法和基于分治思想的算法有所不同:
* 分治法分解成规模相似的类型相同的子问题。
* 减治法直接通过运算将问题的规模减小。问题数量没有增加。
## 0 变治法概述
### 基本思想
1. 变换为同样问题的一个更简单或者更方便 的实例—实例化简(Instance simplification)。
2. 变换为同样实例的不同表现—改变表现(Representation Change).
3. 变换为另一个问题的实例, 这种问题的算法是已知的—问题化简(Problem reduction).
> 根本上是转换问题的思路。
## 1 分治法应用
### 排列问题
### 整数划分问题
### 二分搜索问题
### 二分搜索问题
O(\log n)
* 迭代空间O(1)
* 递归空间O(\log n)
### 大数乘法√
O(n^(log 3))
### 矩阵乘法√
### 快速排序√
### 合并排序√
O(n\log n)
### 线性时间选择√
* 选择最大最小元素-分治或暴力
O(n)
* 选择第k小元素-快排的一半
O(n)
### 最近点对问题√
### 棋盘覆盖问题
## 2 减治法应用
### 拓扑排序
### 生成子集
* 比特串方法
### 假币问题
### 俄式乘法
### 约瑟夫问题
### gcd欧几里得算法
### 插值查找
### 二叉树查找
## 3 变治法应用
### 元素唯一性-预排序算法
### 模式计算-预排序算法
* 问题描述
在给定的数字列表中最经常出现的一个数值称为模式Mode5157657模式是5
* 暴力法O(n^2)
* 预排序O(n\log n)
### 线性方程组-高斯小区算法
* 问题描述
n个线性方程构成的n 元联立方程组
* 高斯消去O(n^3)
### 霍纳法则
* 问题描述
针对一个给定的x 的多项式p(x) = anxn + an-1xn-1 + … + a1x + a0 求值
* 思想
它不断地把x作为公因子从降次以后的剩余多项式中提取出来(x) =(…(anx + an-1)x + ..)x + a0
* 例子
```
p(x) = 2x4 - x3 + 3x2 + x - 5
= x2x3 - x2 + 3x + 1 - 5
= xx2 x2 - x +3+1-5
= xxx2 x-1+3+1-5
```
### lcm 最小公倍数
### AVL树
### 2-3树
### 堆排序
### 二进制幂
### 大数乘法
### 矩阵乘法
### 快速排序
### 合并排序
### 线性时间选择
### 最近点对问题
### 棋盘覆盖问题

View File

@@ -41,4 +41,32 @@ T(n)=\begin{cases}
O(1)& n=1\\
nT(n-1)+O(1)& n>1
\end{cases}
$$
$$
## 2 排列问题-Johnson-Trotter Algorithm
### 算法原理
给一个排列中的每个分量k 赋予一个方向。例如:
$$
\overrightarrow{3}\overleftarrow{2}\overrightarrow{4}\overleftarrow{1}
$$
如果分量k 的箭头指向一个相邻的较小元素,我们说它在这个以箭头标记的排列中是可移动的。3和4是可移动的。
### 算法过程
```
JohnsonTrotter(n)
//输入:一个正整数n
//输出:{1,…,n的所有排列的列表
将第一个排列初始化为
While 存在可移动整数 do
求最大的可移动整数k
把k 和它箭头指向的相邻整数互换
调转所有大于k 的整数的方向
```

View File

@@ -0,0 +1,38 @@
# 大整数乘法
## 1 大整数乘法-分治法
### 问题描述
设u 和v 是两个n 位的整数(二进制),传统的乘法算法需要(n2) 数字相乘来计算u 和v 的乘积。
### 算法原理
* 把每个整数分为两部分每部分为n/2位则u 和v 可重写为u = w2n/2 + x 和v = y2n/2 +z
* u 和v 的乘积可以计算为:
```
uv = w2n/2 + x(y2n/2 +z) = wy2n + (wz + xy) 2n/2 + xz
```
用2^n做乘法运算相当于简单地左移n 位,它需要θ( n) 时间。
* 考虑用以下恒等式计算wz + xy。
```
wz + xy = (w + x) ( y + z) wy xz
```
* 由于wy 和 xz 不需要做二次计算结合以上二式仅需3次乘法运算
```
uv = wy2n + (( w + x) ( y + z) wy xz) 2n/2 + xz
```
### 算法效率
* 此方法产生以下递推式
```
T (n) = d 若n = 1
= 3T(n/2) +bn 若 n>1
```
* 定理得出
$$
T(n) =Θ(n^log 3) = O(n^1.59)
$$

View File

@@ -0,0 +1,44 @@
# 矩阵乘法
## 1 矩阵乘法-STRASSEN算法
### 问题描述
### 算法原理
算法的基本思想在于以增加加减法的次数来减少乘法次数:
用了7次n/2 x n/2 矩阵乘法和18次n/2 x n/2 矩阵的加法
### 算法过程
* 将矩阵分块
```
A = a11 a12
a21 a22
B = b11 b12
b21 b22
```
* 计算分块矩阵的乘法
```
d1 = (a11 + a22) (b11 + b22)
d2 = (a21 + a22) b11
d3 = a11 (b12 b22)
d4 = a22 (b21 b11)
d5 = (a11 + a12) b22
d6 = (a21 a11) (b11 + b12)
d7 = (a12 a22) ( b21 + b22)
```
* 将分块矩阵乘法进行合并
### 算法效率
```
T (n) = m 若n=1
=7T (n/2) + 18(n/2)2 a 若n≥ 2
```
```
T (n) = mnlog7+6anlog7-6an2
即运行时间为Θ (nlog7)= On2.81
```

View File

@@ -0,0 +1,30 @@
## 拓扑排序-减治法
### 问题描述
考虑五门必修课的一个集合{C1, C2, C3, C4, C5},
一个在职的学生必须在某个阶段修完这几门课程。
可以按照任何次序学习这些课程,只要满足下面这些条件:
C1和C2没有任何先决条件
修完C1 和C2才能修C3
修完C3 才能修C4
修完C3、C4才能修C5
这个学生每个学期只能修一门课程。
若用一个图来建模,它的顶点代表课程,有向边表示先决条件,该问题为:是否可以按照这种次序列出它的顶点,使得对于图中每一条边来说,边的起始顶点总是排在边的结束顶点之前。
这个问题称为拓扑排序。
如果有向图具有一个有向的回路,该问题是无解的。因此,为了使得拓扑排序成为可能,问题中的图必须是一个无环有向图。
### 减治法原理
基于减(减一)治技术的一个直接实现:重复以下过程:
在余下的有向图中求出一个源,它是一个没有输入边的顶点;
然后把该源和所有从它出发的边都删除。(如果有多个这样的源,可以任意选择一个;如果这样的源不存在,算法停止,因为该问题是无解的)
顶点被删除的次序就是拓扑排序的一个解。
### 拓扑排序-深度搜索

View File

@@ -0,0 +1,44 @@
# 元素唯一性
## 1 元素唯一性-暴力法
### 问题描述
检验数组中元素的惟一性
### 算法原理
暴力法
```
UniqueElements(A[1,…n])
//输出如果A之元素全部惟一返回“true”, 否则返回 “false”
for i←1 to n-1 do
for j← i+1 to n do
if A[i]=A[j] return false
return true
```
### 算法效率
n(n-1)/2
## 2 元素唯一性-预排序
### 算法原理
```
PresortElementUniqueness(A[1..n])
//先对数组排序来解元素惟一性问题
//输入n个可排序元素构成的一个数组A[1..n]
//输出如果A没有相等的元素返回“true”, 否则返回”false”
对数组A排序
for i← 1 to n-1 do
if A[i] = A[i+1] return false
return true
```
### 算法效率
T(n)=Tsort(n) + Tscan(n) ∈Θ (nlogn) +Θ (n) = Θ (nlogn)

View File

@@ -19,7 +19,10 @@
### 基本步骤
1. 找出最优解的性质,刻画其结构特征。
2. 递推地定义最优值
2. 递推地定义最优值。需要给出状态转移变量
$$
f(n)=f(n-1)+f(n-2)
$$
3. 以自底向上的方式计算出最优解。
4. 根据计算最优值时的到的信息,构造最有解。
@@ -28,8 +31,36 @@
* 重叠子问题
* 备忘录方法(矩阵表格)
### 基本概念
* 阶段;明确问题的各个阶段:将问题划分为相互联系的各个阶段。
* 状态明确问题的各个状态表达每个阶段的状态定义状态变量。描述过程状态的变量称为状态变量。常用xk表示在第k段的某一状态。
* 决策:明确状态从一个阶段到另一个阶段的变化。实现状态转移方程。
* 最优指标函数:用来判断决策过程中的优劣问题,淘汰不好的解,留下最优子结构。决策就是某阶段状态给定以后,从该状态演变到下一阶段某状态的选择。描述决策的变量,称为决策变量。
### 可逆过程
* 顺序解法以G为始端以A为终端的左行解法程序称为顺序解法
* 逆序解法可以把段次颠倒过来求最优解的多阶段决策过程称为可逆过程。
* 顺序解法和逆序解法只表示行进方向的不同或始端的颠倒。但用动态规划方法求最优解时,都是在行进方向规定后,均要逆着这个规定的行进方向,从最后一段向前逆推计算,逐段找出最优途径
### 构建动态规划模型
1. 正确选择状态变量xk, 使它既能描述过程的状态,又要满足无后效性。动态规划中的状态与一般所说的状态概念是不同的,它必须具有三个特性:
* 要能够用来描述受控过程的演变特征。
* 要满足无后效性。 所谓无后效性是指:如果某段状态给定,则在这段以后过程的发展不受前面各阶段状态的影响。
* 可知性。即是规定的各段状态变量的值,由直接或间接都是可以知道的。
2. 确定决策变量uk及每段的允许决策集合Dk(xk)={uk}
3. 写出状态转移方程如果给定第k段状态变量xk的值则该段的决策变量uk一经确定第k+1段状态变量xk+1的值也就完全确定。
4. 列出指标函数Vk,n 关系,并要满足递推性。
## 1 常见问题
### 最长公共子序列
### 矩阵连乘问题
### 凸多边形最优三角剖分
@@ -50,4 +81,21 @@
### 最优二叉搜索树问题
### 序列匹配问题
### 序列匹配问题
----
### 最短路线问题
### 机器负荷问题
### 资源分配问题
### 可靠性问题
### 排序问题
### 设备更新问题
### 计算二项式系数

View File

@@ -23,4 +23,20 @@
方法
* 算法步数的归纳
* 问题规模的归纳
* 问题规模的归纳
### 贪心的核心思想-特点
* 可行的:即它必须满足问题的约束。
* 局部最优:它是当前步骤中所有可行性选择中最佳的局部选择。
* 不可取消:即选择一旦做出,在算法的后面步骤中就无法改变了。
## 2 常见问题
### 分数背包问题
### 最短路径问题
### Dijkstras Algorithm
### Prims
### Kruskals
### Huffman 算法与决策树

View File

@@ -0,0 +1,60 @@
# Huffman算法
## Huffman算法
### 问题描述
一个字符串文件,我们希望尽可能多地压缩文件,但源文件能够很容易地被重建。
用特定的比特串表示每个字符称为字符的编码文件的大小取决于文件中的字符数n。我们可以使用一种定长编码对每个字符赋予一个长度同为m (m≥log2n)的比特串。
设文件中的字符集是C={c1,c2,…, cn}, 又设f(ci), 1≤i≤n,是文件中字符ci的频度即文件中ci出现的次数。
由于有些字符的频度可能远大于另外一些字符的频度,所以用变长的编码。
去除编码的二义性:
当编码在长度上变化时,我们规定一个字符的编码不能是另一个字符编码的前缀(即词头),这种码称为前缀码。
例如如果我们把编码10和101赋予字符“a” 和“b”就会存在二义性不清楚10究竟是“a” 的编码还是字符“b”的编码的前缀。
一旦满足前缀约束,编码即不具备二义性,可以扫描比特序列直到找到某个字符的编码。
### 算法原理
由Huffman算法构造的编码满足前缀约束并且最小化压缩文件的大小。
算法重复下面的过程直到C仅由一个字符组成
* 设ci和cj是两个有最小频度的字符建立一个新节点c它的频度是ci和cj频度的和使ci和cj为c的子节点
* 令C = C-{ci, cj}{c}。
### 算法过程
1. 第一步初始化n个单节点的树为它们标上字母表的字符。把每个字符的概率记在树的根中用来指出树的权重更一般地来说树的权重等于树中所有叶子的概率之和
2. 第二步:重复下面的步骤,直到只剩一棵单独的树:
* 找到两棵权重最小的树, 把它们作为新树中的左右子树,并把其权重之和作为新的权重记录在新的根中。
3. 构建树后然后进行编码从根节点每个路径上左0右1
### 算法效率
O(n\log n)
### 算法实现
```
算法HUFFMAN
输入n个字符的集合C={c1,c2,…, cn}和它们的频度{f(c1), f(c2),…, f(cn)}。
输出C的Huffman树VT
根据频度将所有字符插入最小堆H
V←C T={}
for j←1 to n-1
c←DELETEMIN(H)
c←DELETEMIN(H)
f(v) ← f(c)+ f(c) //新节点v
INSERT (H, v)
V =V{v}
T = T{(v, c), (v, c)} // c, c为T中v的孩子
end for
```

View File

@@ -109,3 +109,7 @@ void iterativeBacktrack ()
### 分支限界与回溯法对比
* 求解目标不同:回溯法的求解目标是找出解空间树中满足约束条件的所有解。而分支限界的求解目标是找出满足约束条件的一个解。这个解可能是最优解。
* 搜索方式不同:回溯法以深度优先的方式搜索解空间。而分支限界法则以广度优先或以最小消耗优先的方式搜索解空间。
## 2 常见问题
### 着色问题

View File

@@ -49,4 +49,28 @@ n=3, C=30, w={16, 15, 15}, v={45, 25, 25}
### 算法原理
![](image/01背包问题-分支限界.png)
### 算法实现
### 算法实现
## 3 01背包问题-动态规划
### 问题描述
0/1同类物品数最大1背包问题可以定义如下
设U={u1,u2,…,un}是一个准备放入容量为C的背包中的n项物品的集合。对于1≤j≤n,令sj和vj分别为第j项物品的体积和价值C,sj,vj和j 都是正整数。
要解决的问题是用U中的一些物品来装 背包这些物品的总体积不超过C然而要使它们的总价值最大。
### 问题分析
导出递归公式,
设V[i,j] 表示从前i项{u1u2…,ui}中取出来的装入体积为j的背包的物品的最大价值。这里i的范围是从0到n, j的范围是从0到C。
要寻求的是值V[n,C]。
有V[0,j]对于所有j的值是0当背包中没有物品。
V[i,0]对于所有i的值为0当没有物品可放到容积为0的背包里。
### 算法原理
```
V[i,j] = 0 若i=0或j=0
=V[i-1,j] 若j<si
=Max{V[i-1,j],V[i-1,j-si]+vi} 若j≥si
```

View File

@@ -0,0 +1,14 @@
# 指派问题
## 1 指派问题-分支限界
### 问题分析
有n项任务要完成恰好有n个人可以分别去完成其中每一项但由于任务性质和个人专长不同因此个人去完成不同的任务的效率或所费时间就有差别由此提出下述问题应当指派哪个人哪项任务使总的效率为最高或花费的总时间为最小
一个指派问题给出系数矩阵或称效率矩阵矩阵的元素cij(>0) (i, j=1, 2,…, n)表示指派第i人去完成第j向任务的效率或时间成本等。解题时我们引入0-1变量xij令 xij=1当指派第i人去完成第j项任务时
=0,当不指派第i人去完成第j项任务时
### 算法原理-匈牙利法
指派问题最优解的性质如果从系数矩阵cij的一行各元素分别减去该行的最小元素得到新矩阵bij 。那么bij为系数矩阵的指派问题的最优解xij和原问题的最优解相同。

View File

@@ -1,5 +1,21 @@
# 随机化算法
### 随机算法的概述
将算法必须对所有可能的输入都正确地求解问题的条件放宽,只要求它的可能不正确性解能够相对安全地忽略掉,比如说它的出现可能性非常低;
而且也不要求对于特定的输入,算法的每一次运行的输出都必须相同。
随机算法可以做如下定义:
它是在接收输入的同时,为了随机选择的目的,还接收一串随机比特流并且在运行过程中使用该比特流的算法。
一个随机算法在不同的运行中对于相同的输入可以有不同的结果。由此得出对于相同的输入两次不同的随机算法的执行时间可能不同。
### 随机算法的优点
* 首先,较之那些我们所知的解决同一问题最好的确定性算法,随机算法所需的运行时间或空间通常常小一些;
* 其次,观察迄今为止已经发明的各种随机算法,我们发现这些算法总是易于理解和实现。
## 1 伪随机数
### 伪随机数的产生

View File

@@ -1,11 +1,26 @@
时间复杂度
时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当问题规模扩大后,程序需要的时间长度增长得有多快。也就是说,对于高速处理数据的计算机来说,处理某一个特定数据的效率不能衡量一个程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。不管数据有多大程序处理花的时间始终是那么多的我们就说这个程序很好具有O(1)的时间复杂度也称常数级复杂度数据规模变得有多大花的时间也跟着变得有多长这个程序的时间复杂度就是O(n)比如找n个数中的最大值而像冒泡排序、插入排序等数据扩大2倍时间变慢4倍的属于O(n^2)的复杂度。还有一些穷举类的算法所需时间长度成几何阶数上涨这就是O(a^n)的指数级复杂度甚至O(n!)的阶乘级复杂度。不会存在O(2*n^2)的复杂度因为前面的那个“2”是系数根本不会影响到整个程序的时间增长。同样地O (n^3+n^2)的复杂度也就是O(n^3)的复杂度。因此我们会说一个O(0.01*n^3)的程序的效率比O(100*n^2)的效率低尽管在n很小的时候前者优于后者但后者时间随数据规模增长得慢最终O(n^3)的复杂度将远远超过O(n^2)。我们也说O(n^100)的复杂度小于O(1.01^n)的复杂度。
容易看出前面的几类复杂度被分为两种级别其中后者的复杂度无论如何都远远大于前者一种是O(1),O(log(n)),O(n^a)等我们把它叫做多项式级的复杂度因为它的规模n出现在底数的位置另一种是O(a^n)和O(n!)型复杂度,它是非多项式级的,其复杂度计算机往往不能承受。当我们在解决一个问题时,我们选择的算法通常都需要是多项式级的复杂度,非多项式级的复杂度需要的时间太多,往往会超时,除非是数据规模非常小。
P类问题的概念
如果一个问题可以找到一个能在多项式的时间里解决它的算法那么这个问题就属于P问题。
NP问题的概念
这个就有点难理解了或者说容易理解错误。在这里强调回到我竭力想澄清的误区上NP问题不是非P类问题。NP问题是指可以在多项式的时间里验证一个解的问题。NP问题的另一个定义是可以在多项式的时间里猜出一个解的问题。比方说我RP很好在程序中需要枚举时我可以一猜一个准。现在某人拿到了一个求最短路径的问题问从起点到终点是否有一条小于100个单位长度的路线。它根据数据画好了图但怎么也算不出来于是来问我你看怎么选条路走得最少我说我RP很好肯定能随便给你指条很短的路出来。然后我就胡乱画了几条线说就这条吧。那人按我指的这条把权值加起来一看神了路径长度98比100小。于是答案出来了存在比100小的路径。别人会问他这题怎么做出来的他就可以说因为我找到了一个比100 小的解。在这个题中找一个解很困难但验证一个解很容易。验证一个解只需要O(n)的时间复杂度也就是说我可以花O(n)的时间把我猜的路径的长度加出来。那么只要我RP好猜得准我一定能在多项式的时间里解决这个问题。我猜到的方案总是最优的不满足题意的方案也不会来骗我去选它。这就是NP问题。当然有不是NP问题的问题即你猜到了解但是没用因为你不能在多项式的时间里去验证它。下面我要举的例子是一个经典的例子它指出了一个目前还没有办法在多项式的时间里验证一个解的问题。很显然前面所说的Hamilton回路是NP问题因为验证一条路是否恰好经过了每一个顶点非常容易。但我要把问题换成这样试问一个图中是否不存在Hamilton回路。这样问题就没法在多项式的时间里进行验证了因为除非你试过所有的路否则你不敢断定它“没有Hamilton回路”。
之所以要定义NP问题是因为通常只有NP问题才可能找到多项式的算法。我们不会指望一个连多项式地验证一个解都不行的问题存在一个解决它的多项式级的算法。相信读者很快明白信息学中的号称最困难的问题——“NP问题”实际上是在探讨NP问题与P类问题的关系。
## 1 时间复杂度
时间复杂度并不是表示一个程序解决问题需要花多少时间,而是当问题规模扩大后,程序需要的时间长度增长得有多快。也就是说,对于高速处理数据的计算机来说,处理某一个特定数据的效率不能衡量一个程序的好坏,而应该看当这个数据的规模变大到数百倍后,程序运行时间是否还是一样,或者也跟着慢了数百倍,或者变慢了数万倍。
NPC问题的定义
同时满足下面两个条件的问题就是NPC问题。首先它得是一个NP问题然后所有的NP问题都可以约化到它。证明一个问题是 NPC问题也很简单。先证明它至少是一个NP问题再证明其中一个已知的NPC问题能约化到它由约化的传递性则NPC问题定义的第二条也得以满足至于第一个NPC问题是怎么来的下文将介绍这样就可以说它是NPC问题了。
不管数据有多大程序处理花的时间始终是那么多的我们就说这个程序很好具有O(1)的时间复杂度也称常数级复杂度数据规模变得有多大花的时间也跟着变得有多长这个程序的时间复杂度就是O(n)比如找n个数中的最大值而像冒泡排序、插入排序等数据扩大2倍时间变慢4倍的属于O(n^2)的复杂度。
还有一些穷举类的算法所需时间长度成几何阶数上涨这就是O(a^n)的指数级复杂度甚至O(n!)的阶乘级复杂度。不会存在O(2*n^2)的复杂度因为前面的那个“2”是系数根本不会影响到整个程序的时间增长。同样地O (n^3+n^2)的复杂度也就是O(n^3)的复杂度。因此我们会说一个O(0.01*n^3)的程序的效率比O(100*n^2)的效率低尽管在n很小的时候前者优于后者但后者时间随数据规模增长得慢最终O(n^3)的复杂度将远远超过O(n^2)。我们也说O(n^100)的复杂度小于O(1.01^n)的复杂度。
容易看出前面的几类复杂度被分为两种级别其中后者的复杂度无论如何都远远大于前者一种是O(1),O(log(n)),O(n^a)等我们把它叫做多项式级的复杂度因为它的规模n出现在底数的位置另一种是O(a^n)和O(n!)型复杂度,它是非多项式级的,其复杂度计算机往往不能承受。当我们在解决一个问题时,我们选择的算法通常都需要是多项式级的复杂度,非多项式级的复杂度需要的时间太多,往往会超时,除非是数据规模非常小。
## P类问题的概念
如果一个问题可以找到一个能在多项式的时间里解决它的算法那么这个问题就属于P问题。
## NP问题的概念
这个就有点难理解了或者说容易理解错误。在这里强调回到我竭力想澄清的误区上NP问题不是非P类问题。NP问题是指可以在多项式的时间里验证一个解的问题。NP问题的另一个定义是可以在多项式的时间里猜出一个解的问题。
比方说我RP很好在程序中需要枚举时我可以一猜一个准。现在某人拿到了一个求最短路径的问题问从起点到终点是否有一条小于100个单位长度的路线。它根据数据画好了图但怎么也算不出来于是来问我你看怎么选条路走得最少我说我RP很好肯定能随便给你指条很短的路出来。然后我就胡乱画了几条线说就这条吧。那人按我指的这条把权值加起来一看神了路径长度98比100小。于是答案出来了存在比100小的路径。别人会问他这题怎么做出来的他就可以说因为我找到了一个比100 小的解。在这个题中找一个解很困难但验证一个解很容易。验证一个解只需要O(n)的时间复杂度也就是说我可以花O(n)的时间把我猜的路径的长度加出来。那么只要我RP好猜得准我一定能在多项式的时间里解决这个问题。我猜到的方案总是最优的不满足题意的方案也不会来骗我去选它。这就是NP问题。
当然有不是NP问题的问题即你猜到了解但是没用因为你不能在多项式的时间里去验证它。下面我要举的例子是一个经典的例子它指出了一个目前还没有办法在多项式的时间里验证一个解的问题。很显然前面所说的Hamilton回路是NP问题因为验证一条路是否恰好经过了每一个顶点非常容易。但我要把问题换成这样试问一个图中是否不存在Hamilton回路。这样问题就没法在多项式的时间里进行验证了因为除非你试过所有的路否则你不敢断定它“没有Hamilton回路”。
之所以要定义NP问题是因为通常只有NP问题才可能找到多项式的算法。我们不会指望一个连多项式地验证一个解都不行的问题存在一个解决它的多项式级的算法。相信读者很快明白信息学中的号称最困难的问题——“NP问题”实际上是在探讨NP问题与P类问题的关系。
## NPC问题的定义
同时满足下面两个条件的问题就是NPC问题。首先它得是一个NP问题然后所有的NP问题都可以约化到它。证明一个问题是 NPC问题也很简单。先证明它至少是一个NP问题再证明其中一个已知的NPC问题能约化到它由约化的传递性则NPC问题定义的第二条也得以满足至于第一个NPC问题是怎么来的下文将介绍这样就可以说它是NPC问题了。
尽管该理论未能证明确实不存在求解这些难问题的高效算法,但是却已证明这些难问题大多数是互相等价的,即:如果我们可以找到针对某一个这类问题的高效算法,那么我们就能找到求解该类问题中其他所有问题的高效算法。
我们把这类 “计算上等价” 的问题称为NP-complete问题.

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB