理论知识
1. 介绍
为什么分析算法?
- 改进算法
- 选择算法
分析算法的指标?
- Correctness(正确性)
- 对于每一个合法输入,算法都会在有限的时间内输出一个满足要求的结果
- Amount of work done(时间复杂度)
- Amount of space used(空间复杂度)
- Simplicity(简单性)
- 尽管并非总是如此,但通常情况下,最简单,最直接的解决问题的方法并不是最有效的。 然而,算法的简单性是期望的特征。
- 它可以使验证算法的正确性更加容易,并且使编写,调试和修改算法程序变得更加容易。
- 选择算法时应考虑生成调试程序所需的时间,但是如果要经常使用该程序,则其效率可能是选择的决定因素。
- Optimality(最优性)
- 我们可以证明定理确定了解决问题所需的操作数的下限。然后,执行该数量操作的任何算法都是最佳的
算法的完整开发步骤:
- Statement of the problem
- Development of a Model
- Design of the algorithm
- Correctness of the algorithm
- Implementation
- Analysis and complexity of the algorithm
- Program testing
- Documentation
2. 分而治之(分治、减治、变治)
- 分治:将原始问题(难以解决的大问题)分解为若干个规模较小的相同的子问题,在逐个解决各个子问题的基础上,得到原始问题的解。
- MAXMIN 问题
- 二分搜索
- 合并排序
- 寻找第K小的元素
- 大整数的乘法
- 矩阵相乘
- 减治:一个问题给定实例的解和同样问题较小实例的解之间的关系。(利用了解之间的关系,也就是说可以减少相应的计算,也可以说是一种时空平衡)
- 分治法是分解的部分需要进行分开的单独计算(需要计算两遍),而减治法则利用了"一个问题给定实例的解和同样问题较小实例的解之间的关系"从而减少了计算量。
- 减去一个常量:
- 插入排序
- 快速排序(每一次运行一次划分算法都只是排好了一个元素)
- 深度优先查找
- 广度优先查找
- 拓扑排序
- 生成排列
- 生成子集
- 减去常量因子:
- 折半查找
- 假币问题
- 减可变规模:
- 二叉查找树
- 变治
- 变换为同样问题的一个更简单或者更方便的实例:实例化简
- 检验数组中元素的惟一性 – 实例化简_预排序
- 模式计算 – 实例化简_预排序
- AVL树 – 二叉排序树
- 变换为同样实例的不同表现:改变表现
- 2-3树、2-3-4树 – 二叉排序树
- 堆和堆排序
- 霍纳法则 – 多项式的计算
- 变换为另一个问题的实例,这种问题的算法是已知的:问题化简
- 背包问题 – 线性规划
3. 动态规划
动态规划是解决多阶段决策过程最优化的一种方法。
多阶段决策问题:
- 由于它的特殊性,可将过程划分为若干互相联系的阶段;
- 在它的每一个阶段都需要作出决策,并且一个阶段的决策确定以后,常影响下一个阶段的决策,从而影响整个过程的活动路线;
- 各个阶段所确定的决策就构成一个决策序列,通常称为一个策略;
- 每一个阶段可供选择的决策往往不止一个,对应于一个策略就有确定的活动效果;
- 多阶段决策问题,就是要在允许选择的那些策略中间,选择一个最优策略,使在预定的标准下达到最好的效果。
动态规划最优化原理:
作为整个过程的最优策略具有这样的性质:即无论过去的状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。
动态规划与与穷举法的对比:
- 减少了计算量
- 丰富了计算结果
- 求出的不是一个最优策略,而是一族的最优策略。(参见动态规划最优化原理)
动态规划解题思路:
- 首先确定状态变量和决策变量;
- 根据决策变量定义状态变量之间的状态转移方程;
- 写出求解变量的递推关系式;
- 定义表格,大小为状态变量 X 决策变量 X 决策次数,根据递推关系式,逐步使用最优决策及其相应的状态填表,最终得到最优解及其决策路线。
4. 贪心算法
贪心算法所做的每一步选择都必须满足:
- 可行的:必须满足问题的约束
- 局部最优:是当前步骤中所有可行性选择中最佳的局部选择
- 不可取消:选择一旦做出,在算法的后面步骤中就无法改变了
最优子结构:对于一个问题,如果它的一个最优解包含了其子问题的最优解,则称该问题具有最优子结构。
什么是拟阵(Matroids):
拟阵理论不能完全覆盖所有的贪心算法(如赫夫曼编码问题),但它可以覆盖大多数具有实际意义的情况。
拟阵是满足条件的一个序对,满足交换性质和遗传性质。
拟阵的通用贪心解法:
Greedy (M, w) {
A ← ϕ;
sort MS into monotonically decreasing order by weight w;
while (MS ≠ ϕ) {
x ← getMax(MS);
if ( A ∪ {x} ∈ Ml )
A ← A ∪ {x};
}
return A;
}
5. 回溯算法
- 任何难问题,均可通过穷尽搜索数量巨大但有限多个可能性而获得一个解。
- 大多数难问题都不存在用穷尽搜索之外的方法来解决问题的算法。
- 产生了开发系统化的搜索技术的需要,并且希望能够将搜索空间减少到尽可能的小。
- 组织搜索的一般技术之一是回溯法。这种算法设计技术可以被描述为有组织的穷尽搜索,它常常可以避免搜索所有的可能性。
回溯法的基本思想:
- 针对所要做的选择构造一棵所谓的状态空间树,树的每一层节点代表了对解的每一个分量所做的选择。
- 用深度优先法搜索状态空间树。
- 在状态空间树中的任一节点,满足一定条件的情况下,搜索回溯。
一般回溯法:
1. v ← Φ
2. flag ← false
3. backrec(1)
4. if flag then output v
5. else output “no solution”
procedure backrec (k)
for 每个 x ∈ Xk
xk ← x; 将xk加入v
if v 为最终解 then set flag ← true and exit
else if v 是部分解 then backrec(k+1)
end for
6. 分支定界
分支定界法的主要思想: 最优化问题是根据某些约束寻求目标函数的最大或最小值。可以利用回溯的思想,且回溯的思想得到进一步的强化。和回溯法相比,分支定界法需要两个额外的条件:
- 对于一棵状态空间树的每一个节点所代表的部分解,我们要提供一种方法,计算出通过这个部分解繁衍出的任何解在目标函数上的最佳值边界。
- 目前求得的最佳解的值。
分支定界解题思路:
- 构造一个搜索树;
- 定义遍历搜索树的原则:前进、分支、回溯、剪枝;
- 不断更新算法的界。
7. NP 完备
- P 问题(easy to find):多项式时间内可解决的问题,当然在多项式时间是可验证的
- NP 问题(easy to check):非确定性多项式时间可解决的问题,但是在多项式时间是可验证的
P 类问题是可以在多项式时间内解决并验证的一类问题,NP 类问题是可以多项式时间验证但是不确定能否在多项式时间内解决的一类问题。
我们通常将多项式时间看作是计算机解决问题的分水岭,因为超过多项式时间之后时间消耗上就不太好接受了。
P=NP 问题在表达什么:是否所有 NP 类问题都可以在多项式时间内解决并验证,也就是转化为 P 类问题。
虽然目前 P=NP 问题还没有被证明或者证伪,但是存在不成立的倾向,即 NPC 问题的发现。
NPC 问题的两个基本特征定义:
- NPC 问题属于 NP 问题;
- 对于所有 NP 问题都可以归约化到它。
NP-Hard 问题是满足 NPC 问题定义的第二条,但不满足第一条,也就是说所有 NP 问题可以归约化到 NPH 问题,但是 NP-Hard 问题不一定是 NP 问题,所以 NPH 问题比 NPC 问题更难。NPH 至少和 NPC 一样难,但是不一定可以在多项式时间内验证,所以可能难于 NP。
- 在 P=NP 成立和不成立情况下的集合关系
8. 近似算法
当 NP 类问题的输入极大时,要求该问题的最优解,算法的执行时间将会是指数级别的。这时,我们很难找到问题的最优解(即使能够找到,花费的代价也是极大的)。因此我们通常会选择在多项式时间内再到问题的一个近似解。
- 多项式近似方案 PTAS (Polynomial-Time Approximation Scheme):若对于每一个固定的 ε>0,算法的运行时间以实例 I 的规模的多项式为上界。
- 完全多项式近似方案 FPTAS (Fully Polynomial-Time Approximation Scheme):在 PTAS 的基础上,我们进一步要求算法 Aε,即算法 Aε 的运行时间以实 I 的规模和 1/ε 的多项式为上界。
FPTAS 被认为是最值得研究的近似算法,仅有极少的 NP-Hard问题存在 FPTAS
9. 随机算法
- Monte Carlo 算法:Monte Carlo 算法每次都能得到问题的解,但不保证所得解的准确性。
- Las Vegas 算法:Las Vegas 算法不会得到不正确的解。一旦用拉斯维加斯算法找到一个解,这个解就一定是正确解。但有时用拉斯维加斯算法找不到解。
可以在Monte Carlo算法给出的解上加一个验证算法,如果正确就得到解,如果错误就不能生成问题的解,这样Monte Carlo算法便转化为了Las Vegas算法。
10. 启发式算法
- 不以达到最优性条件或找到理论上的精确最优解为目标;
- 对目标函数和约束函数的要求通常十分宽松;
- 算法思想都是来自对某种自然规律的模仿,具有人工智能的特点;
- 这些算法的理论工作相对薄弱,一般不能保证收敛到最优解,但是实用性强。
- 遗传算法(Genetic Algorithm,GA)
- 模仿生物种群中优胜劣汰的选择机制,通过种群中优势个体的繁衍进化来实现优化的功能。
- 禁忌搜索(Tabu Search,TS)
- 将记忆功能引入到最优解的搜索过程中,通过设置禁忌区阻止搜索过程中的重复,提高寻优过程的搜索效率。
- 模拟退火(Simulated Annealing,SA)
- 模拟热力学中退火过程能使金属原子达到能量最低状态的机制,通过模拟的降温过程按波尔兹曼方程计算状态间的转移概率来引导搜索,使算法具备很好的全局搜索能力。
- 蚁群算法(Ant Search,ACO)
- 借鉴蚂蚁群体利用信息素相互传递信息来实现路径优化的机理,通过记忆路径信息素的变化来解决组合优化问题。
- 粒子群优化算法(Particle Swarm Optimization ,PSO)
- 模拟鸟类和鱼类群体觅食迁徙中,个体与群体协调一致的机理求解实数优化问题。
- 人工神经网络(Artificial Neural Networks,ANN)
- 从信息处理角度对人脑神经元网络进行模拟,人工神经网络是一种智能运算模型,由大量的节点(神经元)相互联接构成,每个节点包含一种指定的激励函数,每两个节点间的连接用权重来加权,权重通 过一定的机制(如BP算法)来调整。
判断题
1、一个正确的算法,对于每个合法输入,都会在有限的时间内输出一个满足要求的结果。(对)
2、NP 完全问题比其他所有 NP 问题都要难。(错)
错:NP问题分为NP-hard问题和NP完全问题,NP完全问题是最难的,但是NP-hard问题又包含NP完全问题。
错:NP完全问题至少同其他所有NP问题一样难。
3、回溯法用深度优先法或广度优先法搜索状态空间树。(错)
错:回溯法用深度优先法搜索状态空间树。
4、在动态规划中,各个阶段所确定的策略就构成一个策略序列,通常称为一个决策 。(错)
错:在动态规划中,各个阶段所确定的决策构成一个决策序列,通常称为一个策略。
5、P类和NP类问题的关系用P⊂NP来表示是错误的。(错)
错:P中所有问题均属于NP。
P:存在求解判定问题P1的多项式时间算法。
NP:对P1的每一个肯定实例均存在一个多项式时间内的验证。
NP-Complete:P1是一个NP问题,且NP中所有问题都可以多项式转化为P1.
NP-Hard:NP中所有问题都可以多项式转化为P1,但是P1不一定是一个NP问题。
NP-Hard问题范围大于NP-Complete问题范围。
6、若近似算法A求解某极小化问题一实例的解为Sa,且已知该问题的最优解为Sa/3,则该近似算法的性能比为3。(错)
错:性能比是所有实例可能的精确率的上界。3只是这一实例的精确率,不是所有实例的。
7、通常来说,算法的最坏情况的时间复杂性比平均情况的时间复杂性容易计算。(对)
8、若P2多项式时间转化为(polynomial transforms to)P1 ,则P2至少与P1一样难。(错)
错:应该是p1至少和p2一样难,有可能p1更难。
总是可以在可比时间内用P1的算法解决P2,但不能说P1和P2一样难。事实上,有时候可能P2简单而P1更难。
可以将P1比作NPC问题,P2比作NP问题,NPC问题至少和NP一样难,但是可能难于NP。
9、快速排序算法的平均时间复杂度是O(nlogn),使用随机化快速排序算法可以将平均时间复杂度降得更低。(错)
错:排序算法的最快时间复杂度就是O(nlogn)
10、基于比较的寻找数组A[1,…,n]中最大元素的问题下届是Ω(n/3) 。(错)
对:下界理论:问题的下界不唯一,越高越好。算法最优:下界=上界
几个问题的下界:
排序问题:Ω(nlogn)
找最大:Ω(n/2)或Ω(n-1)
找最大最小:Ω(3n/2-2)
找第二大元素:Ω(n+logn-2)
11、O(f(n))+O(g(n))=O(min{f(n),g(n)})。(错)
错。应该是max,O代表的是算法的上界。
12、若f(n)=Ω(g(n)),g(n)=Ω(h(n)),则f(n)=Ω(h(n))。(对)
对:Ω相当于小于等于。
13、若f(n)=O(g(n)),则g(n)=Ω(f(n))。(对)
对:O相当于大于等于。
14、贪婪技术所做的每一步选择所产生的部分解,不一定是可行性的。(错)
错:贪心算法每一步必须满足:可行的(即它必须满足问题的约束)、局部最优、不可撤销。
贪心算法通常包含一个用以寻找局部最优解的迭代过程,在某些实例中这些局部最优解转变成了全局最优解,而在另外一些实例中则无法找到全局最优解。
15、LasVegas 算法只要给出解就是正确的。(对)
对:拉斯维加斯算法不会得到不正确的解。一旦用拉斯维加斯算法找到一个解,这个解就一定是正确解。但有时用拉斯维加斯算法找不到解。与蒙特卡罗算法类似,拉斯维加斯算法找到正确解的概率随着它所用的计算时间的增加而提高。对于所求解问题的任一实例,用同一拉斯维加斯算法反复对该实例求解足够多次,可使求解失败的概率任意小。
16、一个完全多项式近似方案是一个近似方案{Aε},其中每一个算法Aε在输入实例I的规模的多项式时间内运行。 (错)
错:题目中定义的是多项式近似方案。
完全多项式近似方案:是一个近似方案{A_ε},其中每一个算法A_ε在输入实例I的规模和1/ε两者的多项式时间内运行
简述题
1、二叉查找树属于减治策略的三个变种中的哪一个的应用?什么情况下二叉查找树表现出最差的效率?此时的查找和插入算法的复杂性如何?
- 二叉查找树属于减可变规模变种的应用。
- 当先后插入的关键字有序时,构成的二叉查找树蜕变为单支树,树的深度等于n,此时二叉查找树表现出最差的效率。
- 查找和插入算法的时间效率都属于Θ(n)。
2、何谓伪多项式算法?如何将一 Monte Carlo 算法转化为 Las Vegas 算法?
- 若一个数值算法的时间复杂度可以表示为输入数值N的多项式,但其运行时间与输入数值N的二进制位数呈指数增长关系,则称其时间复杂度为伪多项式时间。
- Las Vegas算法不会得到不正确的解。一旦用拉斯维加斯算法找到一个解,这个解就一定是正确解。但有时用拉斯维加斯算法找不到解。
- Monte Carlo算法每次都能得到问题的解,但不保证所得解的准确性。
- 转化:可以在Monte Carlo算法给出的解上加一个验证算法,如果正确就得到解,如果错误就不能生成问题的解,这样Monte Carlo算法便转化为了Las Vegas算法。
3、构造 AVL 树和 2-3 数的主要目的是什么?它们各自有什么样的查找和插入的效率?
- 当先后插入的关键字有序时,构成的二叉查找树蜕变为单支树,树的深度等于n,此时二叉查找树表现出最差的效率,为了解决这一问题,可以构造AVL树或2-3树,使树的深度减小。一棵AVL树要求它的每个节点的左右子树的高度差不能超过1。2-3树和2-3-4树允许一棵查找树的单个节点不止包含一个元素。
- AVL树在最差情况下,查找和插入操作的效率属于Θ(logn)。2-3树无论在最差还是平均情况下,查找和插入的效率都属于Θ(logn)。
4、写出 0/1 背包问题的一个多项式等价(Polynomial Equivalent)的判定问题,并说明为什么它们是多项式等价的。
- 0/1背包问题:从M件物品中,取出若干件放在空间为W的背包里,给出一个能获得最大价值的方案。每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。
- 判定问题I:从M件物品中,取出若干件放在空间为W的背包里,是否存在一个方案,所获价值≥P*?。每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。
- 若判定问题I存在多项式时间的解法,则反复调用该算法就可以在多项式时间内解决0/1背包的优化问题。因而这个判定问题与原问题多项式等价。
5、下面问题是否属于 NP 问题?为什么?
问题表述:给定图𝐺 = (𝑁, 𝐴)中的两个点𝑝、𝑞,整数𝑐和𝑡,图𝐺中每条边的长度𝑐𝑖𝑗及便利这条边的时间
𝑡𝑖𝑗,问图𝐺中是否存在一条由𝑝到𝑞的路径,使得其长度大于𝑐,且遍历时间小于𝑡?
这个问题属于NP问题。因为若给出该问题的一个解,可以在多项式时间内检验这个解的正确性。如给出一条由p到q的路径,可以在多项式时间内计算出它的长度及遍历时间,然后分别与C和t进行比较,从而可以判断这个解的对错。
分治题
一、数组中的逆序对
同力扣题:剑指 Offer 51. 数组中的逆序对
思想:使用分治法,利用归并排序,使用归并时右边大于左边的次数即可计算逆序数目。
时间复杂度的迭代公式为:
- T(n) = 1, n=1;
- T(n) = 2T(n/2) + O(n), n>1
因此算法的时间复杂度为 T(n)=O(nlogn);蛮力法的时间复杂度为 O(n^2),当 n 数目较大时,分治法计算规模远小于蛮力法。
- go 语言源码以及注释:
func reversePairs(nums []int) int {
count := MergeSort(nums, 0, len(nums)-1) // 使用归并排序来计算逆序数目
return count
}
// 合并 [l,r] 两部分数据,mid 左半部分的终点,mid + 1 是右半部分的起点
func merge(arr []int, l int, mid int, r int) int {
// 因为需要直接修改 arr 数据,这里首先复制 [l,r] 的数据到新的数组中,用于赋值操作
temp := make([]int, r-l+1)
for i := l; i <= r; i++ {
temp[i-l] = arr[i]
}
// 指向两部分起点
left := l
right := mid + 1
// 逆序的数目
count := 0
for i := l; i <= r; i++ {
// 左边的点超过中点,说明只剩右边的数据
if left > mid {
arr[i] = temp[right-l]
right++
// 右边的数据超过终点,说明只剩左边的数据
} else if right > r {
arr[i] = temp[left-l]
left++
// 左边的数据大于右边的数据,选小的数字,即右边的数据,此时存在逆序
} else if temp[left-l] > temp[right-l] {
arr[i] = temp[right-l]
right++
count += mid - left + 1 // 逆序的数目为 mid + 1 -left
// 否则选左边的数据,没有逆序
} else {
arr[i] = temp[left-l]
left++
}
}
return count
}
func MergeSort(arr []int, l int, r int) int {
if l >= r {
return 0
}
// 递归向下
mid := (r + l) / 2
leftCount := MergeSort(arr, l, mid) // 左半部分的逆序数目
rightCount := MergeSort(arr, mid+1, r) // 右半部分的逆序数目
// 归并向上
crossCount := merge(arr, l, mid, r) // 交叉项的逆序数目
return leftCount + rightCount + crossCount
}
二、多数元素
同力扣题:169. 多数元素
思想:使用变治法,利用预排序,之后遍历求解多数元素。
因此算法的时间复杂度为 T(n)=O(nlogn);蛮力法的时间复杂度为 O(n^2),当 n 数目较大时,变治法计算规模远小于蛮力法。
- go 语言源码以及注释:
func majorityElement(nums []int) int {
sort.Ints(nums) // 首先排序
majCount := 1 // 多数元素的个数
maj := nums[0] // 多数元素
curCount := 1 // 当前元素的个数
cur := nums[0] // 当前元素
for i := 1; i < len(nums); i++ {
if cur == nums[i] {
curCount++ // 当前元素的个数加一
} else {
// 更新多数元素
if curCount > majCount {
majCount = curCount
maj = cur
}
// 更新当前元素
curCount = 1
cur = nums[i]
}
}
// 更新多数元素
if curCount > majCount {
majCount = curCount
maj = cur
}
return maj
}
动态规划题
一、生产库存问题
- 共需要四次决策:k=1,2,3,4
- 需求量为:Need_k, nk=2,3,2,4
- 状态变量为月初库存:Reservation_k, rk=0,r2,r3,r4,0
- 决策变量为生产量:Production_k, pk=p1,p2,p3,p4
写出状态转移方程:rk+1 = rk + pk - nk
每月的费用为:CurCost_k
- cck = 0.5 (rk - nk), pk=0
- cck = 3 + pk + 0.5 (rk + pk - nk), pk>0
则递推关系式为 k~n 月的最优费用为:Cost_k, ck = min{ck+1 + cck}
且 c5=0,c1 即为所求的最优解。
将三维表(状态变量 X 决策变量 X 决策次数),列为多个二维表(状态变量 X 决策变量),其中某状态下的最优决策使用红色标出。
- k=4, n4=4, r5=r4+p4-n4=0, 且 c4=c5(r5)+cc4
状态/决策 | r4=0 | r4=1 | r4=2 | r4=3 | r4=4 |
---|---|---|---|---|---|
p4=0 | - | - | - | - | r5=0, cc4=0, c4=0 |
p4=1 | - | - | - | r5=0, cc4=4, c4=4 | - |
p4=2 | - | - | r5=0, cc4=5, c4=5 | - | - |
p4=3 | - | r5=0, cc4=6, c4=6 | - | - | - |
p4=4 | r5=0, cc4=7, c4=7 | - | - | - | - |
- k=3, n3=2, r4=r3+p3-n3, 且 c3=c4(r4)+cc3
状态/决策 | r3=0 | r3=1 | r3=2 | r3=3 | r3=4 | r3=5 | r3=6 |
---|---|---|---|---|---|---|---|
p3=0 | - | - | r4=0, cc3=0, c3=7+0=7 | r4=1, cc3=0+0.5=0.5, c3=6+0.5=6.5 | r4=2, cc3=0+1=1, c3=5+1=6 | r4=3, cc3=0+1.5=1.5, c3=4+1.5=5.5 | r4=4, cc3=0+2=2, c3=0+2=2 |
p3=1 | - | r4=0, cc3=4+0=4, c3=7+4=11 | r4=1, cc3=4+0.5=4.5, c3=6+4.5=10.5 | r4=2, cc3=4+1=5, c3=5+5=10 | r4=3, cc3=4+1.5=5.5, c3=4+5.5=9.5 | r4=4, cc3=4+2=6, c3=0+6=6 | - |
p3=2 | r4=0, cc3=5+0=5, c3=7+5=12 | r4=1, cc3=5+0.5=5.5, c3=6+5.5=11.5 | r4=2, cc3=5+1=6, c3=5+6=11 | r4=3, cc3=5+1.5=6.5, c3=4+6.5=10.5 | r4=4, cc3=5+2=7, c3=0+7=7 | - | - |
p3=3 | r4=1, cc3=6+0.5=6.5, c3=6+6.5=12.5 | r4=2, cc3=6+1=7, c3=5+7=12 | r4=3, cc3=6+1.5=7.5, c3+4+7.5=11.5 | r4=4, cc3=6+2=8, c3=0+8=8 | - | - | - |
p3=4 | r4=2, cc3=7+1=8, c3=5+8=13 | r4=3, cc3=7+1.5=8.5, c3=4+8.5=12.5 | r4=4, cc3=7+2=9, c3=0+9=9 | - | - | - | - |
p3=5 | r4=3, cc3=8+1.5=9.5, c3=4+9.5=13.5 | r4=4, cc3=8+2=10, c3=0+10=10 | - | - | - | - | - |
p3=6 | r4=4, cc3=9+2=11, c3=0+11=11 | - | - | - | - | - | - |
- k=2, n2=3, r3=r2+p2-n2, 且 c2=c3(r3)+cc2
状态/决策 | r2=0 | r2=1 | r2=2 | r2=3 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 |
---|---|---|---|---|---|---|---|---|---|---|
p2=0 | - | - | - | r3=0, cc2=0, c2=11 | r3=1, cc2=0.5, c2=10.5 | r3=2, cc2=1, c2=8 | r3=3, cc2=1.5, c2=8 | r3=4, cc2=2, c2=8 | r3=5, cc2=2.5, c2=8 | r3=6, cc2=3, c2=5 |
p2=1 | - | - | r3=0, cc2=4, c2=15 | r3=1, cc2=4.5, c2=14.5 | r3=2, cc2=5, c2=12 | r3=3, cc2=5.5, c2=12 | r3=4, cc2=6, c2=12 | r3=5, cc2=6.5, c2=12 | r3=6, cc2=7, c2=9 | - |
p2=2 | - | r3=0, cc2=5, c2=16 | r3=1, cc2=5.5, c2=15.5 | r3=2, cc2=6, c2=13 | r3=3, cc2=6.5, c2=13 | r3=4, cc2=7, c2=13 | r3=5, cc2=7.5, c2=13 | r3=6, cc2=8, c2=10 | - | - |
p2=3 | r3=0, cc2=6, c2=17 | r3=1, cc2=6.5, c2=16.5 | r3=2, cc2=7, c2=14 | r3=3, cc2=7.5, c2=14 | r3=4, cc2=8, c2=14 | r3=5, cc2=8.5, c2=14 | r3=6, cc2=9, c2=11 | - | - | - |
p2=4 | r3=1, cc2=7.5, c2=17.5 | r3=2, cc2=8, c2=15 | r3=3, cc2=8.5, c2=15 | r3=4, cc2=9, c2=15 | r3=5, cc2=9.5, c2=15 | r3=6, cc2=10, c2=12 | - | - | - | - |
p2=5 | r3=2, cc2=9, c2=16 | r3=3, cc2=10, c2=16.5 | r3=4, cc2=11, c2=17 | r3=5, cc2=12, c2=17.5 | r3=6, cc2=13, c2=15 | - | - | - | - | |
p2=6 | r3=3, cc2=10.5, c2=17 | r3=4, cc2=11, c2=17 | r3=5, cc2=11.5, c2=17 | r3=6, cc2=12, c2=14 | - | - | - | - | - | - |
p2=7 | r3=4, cc2=12, c2=18 | r3=5, cc2=12.5, c2=18 | r3=6, cc2=13, c2=15 | - | - | - | - | - | - | - |
p2=8 | r3=5, cc2=13.5, c2=19 | r3=6, cc2=14, c2=16 | - | - | - | - | - | - | - | - |
p2=9 | r3=6, cc2=15, c2=17 | - | - | - | - | - | - | - | - | - |
- k=1, n1=2, r2=r1+p1-n1, 且 c1=c2(r2)+cc1
状态/决策 | r1=0 | r1=1 | r1=2 | r1=3 | r1=4 | r1=5 | r1=6 | r1=7 | r1=8 | r1=9 | r1=10 | r1=11 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
p1=0 | - | - | r2=0 | r2=1 | r2=2 | r2=3 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 |
p1=1 | - | r2=0 | r2=1 | r2=2 | r2=3 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - |
p1=2 | r2=0 | r2=1 | r2=2 | r2=3 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - | - |
p1=3 | r2=1 | r2=2 | r2=3 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - | - | - |
p1=4 | r2=2 | r2=3 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - | - | - | - |
p1=5 | r2=3, cc1=9.5, c1=20.5 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - | - | - | - | - |
p1=6 | r2=4 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - | - | - | - | - | - |
p1=7 | r2=5 | r2=6 | r2=7 | r2=8 | r2=9 | - | - | - | - | - | - | - |
p1=8 | r2=6 | r2=7 | r2=8 | r2=9 | - | - | - | - | - | - | - | - |
p1=9 | r2=7 | r2=8 | r2=9 | - | - | - | - | - | - | - | - | - |
p1=10 | r2=8 | r2=9 | - | - | - | - | - | - | - | - | - | - |
p1=11 | r2=9 | - | - | - | - | - | - | - | - | - | - | - |
部分省略,其中
- 最优成本为 20.5
- 最优决策为:5->0->6->0
- 最优状态为:0->3->0->4->0
二、项目投资问题
- 共需要三次决策:k=1,2,3
- 状态变量为项目 k~n 的投资额:X_k
- 决策变量为项目 k 的投资额:U_k
- 项目 k 投资 U_k 的盈利为:g_k(U_k)
- 项目 k~n 投资 X_k 的盈利为:f_k(X_k)
写出状态转移方程:X_k+1 = X_k - U_k
则递推关系式为投资项目 k~n 的最优利润为:f_k(X_k)=max{g_k(U_k) + f_k+1(X_k+1)}
且 f_1(8) 即为所求的最优解。
将三维表(状态变量 X 决策变量 X 决策次数),列为多个二维表(状态变量 X 决策变量),其中某状态下的最优决策使用红色标出。
- k=3
状态/决策 | u3=0 | u3=1 | u3=2 | u3=3 | u3=4 | u3=5 | u3=6 | u3=7 | u3=8 |
---|---|---|---|---|---|---|---|---|---|
x3=u3 | f3(0)=0 | f3(1)=4 | f3(2)=26 | f3(3)=40 | f3(4)=45 | f3(5)=50 | f3(6)=51 | f3(7)=52 | f3(8)=53 |
- k=2
状态/决策 | u2=0 | u2=1 | u2=2 | u2=3 | u2=4 | u2=5 | u2=6 | u2=7 | u2=8 |
---|---|---|---|---|---|---|---|---|---|
x2=0, g2=0 | x3=0,f2=0 | - | - | - | - | - | - | - | - |
x2=1, g2=5 | x3=1,f2=10 | x3=0,f2=5 | - | - | - | - | - | - | - |
x2=2, g2=15 | x3=2 | x3=1,f2=20 | x3=0,f2=15 | - | - | - | - | - | - |
x2=3, g2=40 | x3=3 | x3=2 | x3=1,f2=45 | x3=0,f2=40 | - | - | - | - | - |
x2=4, g2=60 | x3=4 | x3=3 | x3=2 | x3=1,f2=65 | x3=0,f2=60 | - | - | - | - |
x2=5, g2=70 | x3=5 | x3=4 | x3=3 | x3=2 | x3=1,f2=75 | x3=0,f2=70 | - | - | - |
x2=6, g2=73 | x3=6 | x3=5 | x3=4 | x3=3 | x3=2 | x3=1,f2=78 | x3=0,f2=73 | - | - |
x2=7, g2=74 | x3=7 | x3=6 | x3=5 | x3=4 | x3=3 | x3=2 | x3=1,f2=79 | x3=0,f2=74 | - |
x2=8, g2=75 | x3=8 | x3=7 | x3=6 | x3=5 | x3=4 | x3=3 | x3=2 | x3=1,f2=80 | x3=0,f2=75 |
- k=1
状态/决策 | u1=0 | u1=1 | u1=2 | u1=3 | u1=4 | u1=5 | u1=6 | u1=7 | u1=8 |
---|---|---|---|---|---|---|---|---|---|
x1=0, g1=0 | x2=0 | - | - | - | - | - | - | - | - |
x1=1, g1=5 | x2=1 | x2=0 | - | - | - | - | - | - | - |
x1=2, g1=15 | x2=2 | x2=1 | x2=0 | - | - | - | - | - | - |
x1=3, g1=40 | x2=3 | x2=2 | x2=1 | x2=0 | - | - | - | - | - |
x1=4, g1=80 | x2=4 | x2=3 | x2=2 | x2=1 | x2=0 | - | - | - | - |
x1=5, g1=90 | x2=5 | x2=4 | x2=3 | x2=2 | x2=1 | x2=0 | - | - | - |
x1=6, g1=95 | x2=6 | x2=5 | x2=4 | x2=3 | x2=2 | x2=1 | x2=0 | - | - |
x1=7, g1=98 | x2=7 | x2=6 | x2=5 | x2=4 | x2=3 | x2=2 | x2=1 | x2=0 | - |
x1=8, g1=100 | x2=8 | x2=7 | x2=6 | x2=5 | x2=4 | x2=3 | x2=2 | x2=1 | x2=0 |
部分省略,其中
- 最优理论为 140
- 最优决策为:4->4->0
- 最优状态为:8->4->0
分支定界题
一、网络搭建问题
- 可以根据线路(l1,l2,…,lm)的取舍构建一棵m层二叉搜索树。第i层的所有左分支表示铺设线路li,右分支则表示不铺设。如果存在可行解,遍历此二叉搜索树即可找到最优解。
- 遍历原则:
- 前进:当前节点未被剪枝并且仍有子节点即可继续前进。
- 分支:先遍历左分支,后遍历右分支。
- 回溯:左右分支都被遍历时返回父节点。
- 剪枝:剪枝条件如下:
- 有环路
- 当前地井数 + 地井数下界 > UMAX
- 当前跨区铺设线路数 + 跨区铺设线路数下界 > DMAX
- 当前费用 + 费用下界 >= 已知最优方案的费用
- 子问题的下界为费用下界、地井数下界、跨区线路数下界。费用下界是根据剩余站点数量定义的,累计最小的路线花费即可得到。由于限制被极度弱化,所以非常粗糙,但是正确有效。另外两个下界也类似。父问题的上界是已知最优方案的费用,显然正确有效。
按费用从小到大排序所有路线l1,l2,...,lm
计算子问题下界:
1。费用下界:剩余站点数量->最小花费 #累计最小的线路花费即可得到,下同
2。地井数下界:剩余站点数量->最小地井数
3。跨区线路数下界:剩余站点数量->最小跨区线路数
search(空集, l1)
返回最优结果
def search(线路集合S,当前线路l):
判断线路集合S是否合格,条件如下:
1。无环路
2。当前地井数 + 地井数下界 <= UMAX
3。当前跨区铺设线路数 + 跨区铺设线路数下界 <= DMAX
4。当前费用 + 费用下界 < 已知最优方案的费用
如果合格:
当前网络已经覆盖所有站点:
记S为已知最优
否则若剩下的线路数有可能使所有站点构成网络:
search(S ∪ {l}, l的下一条路线)
search(S, l的下一条路线)
二、贸易关税问题
- 可以根据除A外的51个国家定义一棵若干层二叉搜索树。每个节点的左分支表示选择其代表的国家为下一个贸易顺序上的国家,右分支则表示不选择。构造搜索树需要两个辅助变量,之前的贸易顺序S(s为S的最后一个国家)和这一轮否决的国家V。任取可以和s国贸易的国家c(不属于S和V)置于树的当前生成位置,然后用(S’ = <S, c>和V’ = 空集)生成左子树,用(S’ = S和V’ = V ∪ {c})生成右子树。如果c不存在或者s = B则终止当前子树的生成。如此反复可以建立一棵二叉搜索树。
- 遍历原则:
- 前进:当前节点未被剪枝并且仍有子节点即可继续前进。
- 分支:先遍历左分支,后遍历右分支。
- 回溯:左右分支都被遍历时返回父节点。
- 剪枝:剪枝条件如下:
- 当前税费 + s国与B国贸易的最小税费 >= 已知最优方案的税费
- 当前时间 + s国与B国贸易的最短时间 > t
- 子问题的下界为税费下界和时间下界,均由dijkstra算法算法得到,表示某国与B国贸易的最小税费和最短时间。两个结果均由弱化限制的方法得到,所以是正确的,计算复杂度也不高,当然有效。父问题的上界是已知最优方案的税费,显然正确有效。
使用Dijkstra算法得到子问题下界:
1、税费下界:某国与B国贸易的最小税费,顺便记录对应的事件和贸易顺序
2、时间下界:某国与B国贸易的最短时间
search(<A>, <V>)
返回最优结果
def search(贸易顺序S, 否决的国家V):
令s为S的最后一个国家
判断S是否合格,条件如下:
1.当前税费 + s国与B国贸易的最小税费 < 已知最优方案的税费
2.当前时间 + s国与B国贸易的最短时间 <= t
如果合格:
当前时间 + s国与B国贸易的最小税费对应的时间 <= t:
记<S,s国与B国贸易的最小税费对应贸易顺序(不包括s)>为已知最优
否则对与s国贸易的不属于S和不属于V的国家c:
search(<S, c>, V)
search(<S>, <V, c>)