为什么分析算法?
分析算法的指标?
算法的完整开发步骤:
动态规划是解决多阶段决策过程最优化的一种方法。
多阶段决策问题:
动态规划最优化原理:
作为整个过程的最优策略具有这样的性质:即无论过去的状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略。
动态规划与与穷举法的对比:
动态规划解题思路:
贪心算法所做的每一步选择都必须满足:
最优子结构:对于一个问题,如果它的一个最优解包含了其子问题的最优解,则称该问题具有最优子结构。
什么是拟阵(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;
}
回溯法的基本思想:
一般回溯法:
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
分支定界法的主要思想: 最优化问题是根据某些约束寻求目标函数的最大或最小值。可以利用回溯的思想,且回溯的思想得到进一步的强化。和回溯法相比,分支定界法需要两个额外的条件:
分支定界解题思路:
P 类问题是可以在多项式时间内解决并验证的一类问题,NP 类问题是可以多项式时间验证但是不确定能否在多项式时间内解决的一类问题。
我们通常将多项式时间看作是计算机解决问题的分水岭,因为超过多项式时间之后时间消耗上就不太好接受了。
P=NP 问题在表达什么:是否所有 NP 类问题都可以在多项式时间内解决并验证,也就是转化为 P 类问题。
虽然目前 P=NP 问题还没有被证明或者证伪,但是存在不成立的倾向,即 NPC 问题的发现。
NPC 问题的两个基本特征定义:
NP-Hard 问题是满足 NPC 问题定义的第二条,但不满足第一条,也就是说所有 NP 问题可以归约化到 NPH 问题,但是 NP-Hard 问题不一定是 NP 问题,所以 NPH 问题比 NPC 问题更难。NPH 至少和 NPC 一样难,但是不一定可以在多项式时间内验证,所以可能难于 NP。
当 NP 类问题的输入极大时,要求该问题的最优解,算法的执行时间将会是指数级别的。这时,我们很难找到问题的最优解(即使能够找到,花费的代价也是极大的)。因此我们通常会选择在多项式时间内再到问题的一个近似解。
FPTAS 被认为是最值得研究的近似算法,仅有极少的 NP-Hard问题存在 FPTAS
可以在Monte Carlo算法给出的解上加一个验证算法,如果正确就得到解,如果错误就不能生成问题的解,这样Monte Carlo算法便转化为了Las Vegas算法。
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、二叉查找树属于减治策略的三个变种中的哪一个的应用?什么情况下二叉查找树表现出最差的效率?此时的查找和插入算法的复杂性如何?
2、何谓伪多项式算法?如何将一 Monte Carlo 算法转化为 Las Vegas 算法?
3、构造 AVL 树和 2-3 数的主要目的是什么?它们各自有什么样的查找和插入的效率?
4、写出 0/1 背包问题的一个多项式等价(Polynomial Equivalent)的判定问题,并说明为什么它们是多项式等价的。
5、下面问题是否属于 NP 问题?为什么?
问题表述:给定图 = (, )中的两个点、,整数和,图中每条边的长度及便利这条边的时间
,问图中是否存在一条由到的路径,使得其长度大于,且遍历时间小于?
这个问题属于NP问题。因为若给出该问题的一个解,可以在多项式时间内检验这个解的正确性。如给出一条由p到q的路径,可以在多项式时间内计算出它的长度及遍历时间,然后分别与C和t进行比较,从而可以判断这个解的对错。
同力扣题:剑指 Offer 51. 数组中的逆序对
思想:使用分治法,利用归并排序,使用归并时右边大于左边的次数即可计算逆序数目。
时间复杂度的迭代公式为:
因此算法的时间复杂度为 T(n)=O(nlogn);蛮力法的时间复杂度为 O(n^2),当 n 数目较大时,分治法计算规模远小于蛮力法。
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 数目较大时,变治法计算规模远小于蛮力法。
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
}
写出状态转移方程:rk+1 = rk + pk - nk
每月的费用为:CurCost_k
则递推关系式为 k~n 月的最优费用为:Cost_k, ck = min{ck+1 + cck}
且 c5=0,c1 即为所求的最优解。
将三维表(状态变量 X 决策变量 X 决策次数),列为多个二维表(状态变量 X 决策变量),其中某状态下的最优决策使用红色标出。
状态/决策 | 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 | - | - | - | - |
状态/决策 | 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 | - | - | - | - | - | - |
状态/决策 | 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 | - | - | - | - | - | - | - | - | - |
状态/决策 | 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 | - | - | - | - | - | - | - | - | - | - | - |
部分省略,其中
写出状态转移方程: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 决策变量),其中某状态下的最优决策使用红色标出。
状态/决策 | 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 |
状态/决策 | 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 |
状态/决策 | 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 |
部分省略,其中
按费用从小到大排序所有路线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的下一条路线)
使用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>)