BUAA算法作业-1
0 参考资料
- Concrete Mathematics : A Foundation for Computer Science
1 题目
1.1 递推式求解
请由定理1导出
定理1:设
为非负整数, 为非负常数,并对于某个非负整数 ,令 ,则以下递推式 的解是
解:为使得
由定理1可知,
因此
其渐进复杂性为
1.2 算法和 算法集成
由于Prim算法和Kruskal算法设计思路的不同,导致了其对不同问题实例的效率对比关系的不同。请简要论述:
1、如何将两种算法集成,以适应问题的不同实例输入?
2、你如何评价这一集成的意义?
解:首先介绍
算法
- 从任意一个根节点开始构建树集合
,每次选取树集合 外距离 最近的节点加入树集合中,直至得到 的最小生成树(覆盖 中所有节点)。 - 时间总代价为
算法
- 在所有连接森林中两棵不同树的边中,选取最小权值边,直至得到
的最小生成树(覆盖 中所有节点)。 - 先将所有边按权重排序,然后逐个加入不构成环的边,直到生成MST
- 时间总代价为
,这是考虑到 得到的结论
显然,对于稠密图(具有大量边,而且边的数量接近于顶点数量的平方)或小规模图(顶点数量较少的图)而言(
而对于稀疏图(边的数量相对于顶点数量较少的图)或大规模图(顶点数量较多、边的数量较少)的情况而言(
因此,对于本题,我们可以得到以下结论:
- 集成方法
- 对于稠密图或小规模图而言,优先考虑
算法;对于稀疏图或大规模图而言,优先考虑 算法。 - 此外,对于一些特殊场景,如需要实时更新最小生成树的场景,
算法由于其局部性质和易于维护的特点,更适合动态变化的情况。
- 对于稠密图或小规模图而言,优先考虑
- 集成的意义
- 集成的意义在于面对不同类型的问题实例时能够选择更为高效的算法,在集成后,算法应对不同规模的输入时会呈现比较稳定的时间代价,提高算法的整体效率。然而,二者相差不过是常数级别的时间代价(考虑到
函数几乎可以视为视为常数),通常情况下执行时间差距不会很大。
- 集成的意义在于面对不同类型的问题实例时能够选择更为高效的算法,在集成后,算法应对不同规模的输入时会呈现比较稳定的时间代价,提高算法的整体效率。然而,二者相差不过是常数级别的时间代价(考虑到
1.3 全排列算法分析
分析以下生成排列算法的正确性和时间效率:
HeapPermute(n):
//实现生成排列的Heap算法
//输入:一个正整数n和一个全局数组A[1..n]
//输出:A中元素的全排列
if n = 1
write A
else
for i←1 to n do
HeapPermute(n-1)
if n is odd
swap A[1]and A[n]
else
swap A[i]and A[n]
解:这个生成全排列的算法伪代码是正确的,算法生成的排列满足不重不漏的原则。下面证明其正确性,并分析其时间效率:
1、正确性:考虑使用归纳法证明本算法的正确性。
时,显然 是 的全排列,算法正确。 时,算法输出 和 正确,且运行结束后保持 顺序不变。 时,算法输出 、 、 、 、 、 正确,且运行结束后交换 、 得到 ,为原排列顺序。- 假设
时算法成立,即 能够正确生成前 个元素的全排列,且满足 为奇数时,运行结束后数组顺序不变; 为偶数时,运行结束后数组向右移动一位。 - 当
时- 在
为偶数时,由于 生成了前 个元素的全排列,且 为奇数,运行结束后元素顺序不变,此时交换 和 实现前 个元素的更新。随着 从 增长到 ,实现了所有元素都在最后一位呆过的现象,从而 能够正确生成全排列。 - 在
为奇数时,由于 生成了前 个元素的全排列,且 为偶数,运行结束后元素顺序向右移动一位,此时交换 和 能够将新的元素更新到前 个中。随着 从 增长到 ,实现了所有元素都在最后一位呆过的现象,从而 能够正确生成全排列。
- 在
- 从而对于任意
,上述算法能够正确生成全排列。
2、时间效率
-
首先写出时间复杂度
的递推关系式-
-
可得
-
-
显然
-
-
事实上,显然
,因此在递推式中可以将多余项 合并,近似得到
1.4 最小元素位置问题
对于求n个实数构成的数组中最小元素的位置问题,写出你设计的具有减治思想算法的伪代码,确定其时间效率,并与该问题的蛮力算法相比较。
解:首先给出蛮力算法如下,显然对应的时间复杂度为
FindMin_BF():
//输入:一个数组A[1..n]
//输出:A中最小元素的位置
min = A[1], pos = 1
for i←1 to n do
if A[i] < min
pos = i
write pos
具有减治思想算法的伪代码如下:
FindMin(k):
//输入:一个全局数组A[1..n]
//输出:A[:k]中最小元素及其位置
if k = 1
return A[1], 1
min, pos = FindMin(k-1)
if A[k] < min
min, pos = A[k], pos
return min, pos
由于每次减治时问题规模减
1.5 约瑟夫斯问题
请给出约瑟夫斯问题的非递推公式
解:首先介绍约瑟夫斯问题的定义。
约瑟夫斯问题:在犹太罗马战争期间,他们41名犹太反抗者困在了罗马人包围的洞穴中。这些反抗者宁愿自杀也不愿被活捉,于是决定围成一个圆圈,并沿着圆圈每隔两个人杀死一个人,直到剩下最后两个人为止。但是,约瑟夫和一个未被告发的同谋者不希望无谓地自杀,于是他迅速计算出他和其朋友在这个险恶的圆圈中应该站的位置
为一般化这一问题,我们在此假设每隔
1、q=1时引理
此时对应每隔1人杀死1人,显然有:
-
偶数情况下:
-
-
奇数情况下:
-
-
因此得到递推表
-
令
,其中 为不超过 的最大幂, 为余数,则有:-
-
证明:对
使用第二数学归纳法 时,必有 ,此时 ,结论成立- 假设
时成立,- 若
,则 - 若
,则
- 若
- 故
对所有的 成立。
-
-
因此有
-
-
事实上,
有更加简单(直接)的计算公式:- 关键在于使用二进制表示
,其中 为 的二进制表示中 的个数,例如 ,在此不再证明,原理是使用移位公式来表示 的递推
- 关键在于使用二进制表示
2、讨论约瑟夫在当年面临的
-
利用类似的方法可以得到
-
-
其中
分别对应 的情况
-
-
这个递归式的难度远超
的情况,几乎不能继续求解下去了,但是我们可以给出求解的伪代码:-
N:=3n while N > n do N:=floor((N-n-1)/2)+N-n J3(n):=N
-
-
为简化伪代码中的复杂赋值,我们可以使用另外的方法简化这一计算过程,即令
来替换 ,伪代码变为:-
D:=1 while D <= 2n do D:=ceil(3D/2) J3(n):=3n+1-D
-
3、一般化问题:针对任意
-
给出伪代码
-
D:=1 while D <= (q-1)n do D:=ceil(qD/(q-1)) Jq(n):=qn+1-D
-
-
其中,
定义为 -
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步