Algorithm homework 1

1、已知下列递推式:

\[C(n)= \begin{cases} 1 & , & n = 1 \\ 2C(n/2) + n - 1& , & n \geq 2 \end{cases} \]

请由定理1 导出C(n)的非递归表达式并指出其渐进复杂性.算法

定理1:设\(a,c\)为非负整数,\(b,d,x\)为非负常数,并对于某个非负整数\(k\), 令\(n=c^k\), 则如下递推式数组

\[f(n)= \begin{cases} d & , & n=1 \\ af(n/c)+bn^x& , & n\geq2 \end{cases} \]

的解是优化

\[f(n)= \begin{cases} bn^xlog_cn + dn^x & , & n=1 \\ \left( d + \frac{bc^x}{a-c^x} \right)n^{log_ca} - \left( \frac{bc^x}{a-c^x}\right)n^x& , & n\geq2 \end{cases} \]


\(T(n) = C(n) - 1\),则spa

\[T(n)= \begin{cases} 0 & , & n = 1 \\ 2T(n/2) + n & , & n \geq 2 \end{cases} \]

\(T(n)\)知足定理1中递推式,且\(a = 2, b = 1, c = 2, d = 0, x = 1\), 即有\(2 = 2^1\)
故当\(n = 2^k\)时,\(T(n)\)的解为设计

\[T(n) = nlog_2n \]

\(C(n)\)的非递归表达式为code

\[C(n) = T(n) + 1 = nlog_2n + 1 \]

因此其渐进复杂性为\(\Theta(nlog_2n)\)排序

2、因为Prim算法和Kruskal 算法设计思路的不一样,致使了其对不一样问题实例的效率对比关系的不一样。请简要论述:

一、如何将两种算法集成,以适应问题的不一样实例输入;

Prim算法基于每一个点, 要遍历全部的点。
Kruskal算法基于边, 要遍历许多边。
所以能够在边比较稀疏的状况下用Kruskal算法,在边较稠密的状况下使用Prim算法.递归

二、你如何评价这一集成的意义?

​ 一般实现下Prim是\(O(V^2)\)的时间复杂度,但可使用优先队列将时间复杂度优化到\(O(Elog_2V)\),而Kruskal使用排序+并查集实现的复杂度为\(O(Elog_2E)\),二者最优时间复杂度差异仅为log级别的,且Prim平均状况下效果会更好。所以这一集成大概只是增长了代码复杂度,仅用Prim算法的效果可能会更好。队列

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. 正确性

设 k 为正整数且 $ k \leq n\(,记\)A[1..n]\(为\)A=[a_1, a_2, \cdots, a_n]$数学

咱们有如下结论:在执行算法\(HeapPermute(k)\)后, 输出 A 前 k 位的全排列,后\(n − k\)位不变。(特别地, 当 k = n 时, 输出的就是 A 的全排列。) 执行算法\(HeapPermute(k)\)先后, 当 k 为奇数时, A 保持不变;当n为偶数时, A 的前 k 位循环右移一位。

下面数学概括法证实该结论:
证实

  • (1) 当\(k = 1\)时,算法\(HeapPermute(k)\)输出\([a_1, a_2, \cdots, a_n]\),与结论相符。
  • (2) 假设当$k = 2j - 1(j \(为正整数\))\(,且\)k < n \(时,执行\)HeapPermute(k)\(输出 A 前 k 位的全排列,后\)n − k\(位不变,且A保持不变。则当\)k = 2j\(时,对于\)i = 1, 2, \cdots, 2j$时,分别输出A的前\(2j-1\)位的全排列,A的后\((n - 2j + 1)\)位不变,程序向下执行到第10行,因为n为偶数,则\(swap(a_i,a_{2j})\)。以前全部操做仅改变A数组的前\(2j\)位,而后输出\(2j - 1\)位,后后\((n - 2j + 1)\)位不变。最后依次将A的第\(1, 2, \cdots, 2j\)位交换到第2m位。所以上述操做获得了A的前2j位的全排列且前2j位循环右移一位,后\(n-2j\)位不变。与结论相符。
  • (3) 假设当$k = 2j(j \(为正整数\))\(,且\)k < n\(时,,执行\)HeapPermute(k)\(输出 A 前 k 位的全排列,后\)n − k\(位不变,且 A 的前 k 位循环右移一位。相似的可获得当\)k=2j+1$时, A 保持不变。

所以结论得证,执行算法HeapPermute(n)能够输出全局数组\(A = [1..n]\)的全排列。

2. 时间效率

考虑交换操做的耗时,有递推公式以下:

\[T(n)= \begin{cases} 1 & , & n = 1 \\ n\left[T(n - 1) + 1\right] & , & n \geq 2 \end{cases} \]

化简得\(T(n) = n! + O(n^{n-1})\)

\(T(n)\)的时间复杂度为\(O(n!) + O(n^{n-1})\)

4、对于求n 个实数构成的数组中最小元素的位置问题,写出你设计的具备减治思想算法的伪代码,肯定其时间效率,并与该问题的蛮力算法相比较。

FindMin(n)
    //实现寻找数组中最小元素的位置
    //输入:一个正正整数n和一个全局数组A[1..n]
    //输出:A中最小元素m及其位置a
    if n == 1:
        return A[1], 1
    else
        m, a = FindMin(n-1)
    if m <= A[n]:
        return m, a
    else
        return A[n], n

上述减治方法每次将问题的规模约减1,所以时间复杂度为\(O(n)\),与该问题的蛮力算法时间复杂度相同。

5、请给出约瑟夫斯问题的非递推公式 J(n),并证实之。其中,n 为最初总人数,J(n) 为最后幸存者的最初编号。

约瑟夫问题的非递推公式为:

\[J(n) = 1 + 2(n - 2^{\lfloor log_2n \rfloor}), \ n = 1, 2, 3, \cdots \]

\(m = {\lfloor log_2n \rfloor}\)\(l = n - 2^m,\)\(J(n) = 2l+1\)
首先咱们很容易知道该问题的通项公式为

\[\begin{array}{l} J(2n) = 2J(n) - 1 & , & n 为偶数 \\ J(2n + 1) = 2J(n) + 1 & ,& n为奇数 \end{array} \]

下用概括法证实该通项。
证实

  1. \(n = 1\)时,上式显然成立。
  2. 假设\(n\)是偶数,取\(m_一、l_1\)使得\(n/2=2^{m_{1}}+l_{1}\),且\(0\leq l_{1}<2^{{m_{1}}}\)。这里\(l_{1}=l/2\)。咱们有\(f(n)=2f(n/2)-1=2((2l_{1})+1)-1=2l+1\),其中第二个等式从概括假设推出。
  3. 假设\(n\)是奇数,则咱们选择\(l_{1}\)\(m_{1}\),使得\((n-1)/2=2^{{m_{1}}}+l_{1}\),且\(0\leq l_{1}<2^{{m_{1}}}\)。注意\(l_{1}=(l-1)/2\)。咱们有\(f(n)=2f((n-1)/2)+1=2((2l_{1})+1)+1=2l+1\),其中第二个等式从概括假设推出。证毕。

综上,对全部的天然数n,原结论成立。证毕。

相关文章
相关标签/搜索