南京邮电大学 算法设计与分析 课后习题

慢慢更新。

第二章

2-8

确定划线语句执行次数、计算渐近时间复杂度

i=1; x=0;
do{
	x++; i=2*i;
} while i<n;

答案: 设语句执行了k次, 2 k ≥ n 2^k \ge n 2kn 时退出循环,因此划线语句执行了 ⌈ l o g 2 n ⌉ \lceil log_2 n \rceil log2n 次。渐进时间复杂度 O ( l o g 2 n ) O(log_2 n) O(log2n) .

for (int i=1;i<=n;i++)
	for (int j=1;j<=i;j++)
		for (int k=1;k<=j;k++)
			x++;

∑ i = 1 n ∑ j = 1 i ∑ k = 1 j 1 = ∑ i = 1 n ∑ j = 1 i j = ∑ i = 1 n i ( i + 1 ) 2 = 1 2 [ ∑ i = 1 n i + ∑ i = 1 n i 2 ] = n ( n + 1 ) ( n + 2 ) 6 \begin{align} \sum_{i=1}^n\sum_{j=1}^i\sum_{k=1}^j1=\sum_{i=1}^n\sum_{j=1}^ij&=\sum_{i=1}^n\frac{\mathrm{i}(i+1)}{2} \\&=\frac{1}{2}[\sum_{i=1}^n i+\sum_{i=1}^n i^2] \\&=\frac{n(n+1)(n+2)}{6} \end{align} i=1nj=1ik=1j1=i=1nj=1ij=i=1n2i(i+1)=21[i=1ni+i=1ni2]=6n(n+1)(n+2)

因为 ∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^{n}i^{2}={\frac{n(n+1)(2n+1)}{6}} i=1ni2=6n(n+1)(2n+1)

x=n; y=0;
while(x>=(y+1)(y+1)) y++;

答案: 解:当 ( y + 1 ) 2 ≤ n (y+1)^2\leq n (y+1)2n 时执行划线语句,即 : y ≤ ⌊ n ⌋ − 1 :y\leq\left\lfloor\sqrt{n}\right\rfloor-1 :yn 1 时执行。
又因为 y 从0开始,因此0~ ⌊ n ⌋ − 1 \lfloor\sqrt{\mathrm{n}}\rfloor_{-1} n 1 共执行 ⌊ n ⌋ \lfloor\sqrt{\mathrm{n}}\rfloor n 次。

渐近时间复杂度为: O ( n ) O(\sqrt{n}) O(n )

m=0;
for (int i=1;i<n;i++)
	for (int j=2*i;j<=n;j++)
		m++;

答案:
∑ i = 0 ⌊ n 2 ⌋ ∑ 2 i n 1 = ∑ i = 0 ⌊ n 2 ⌋ ( n − 2 i + 1 ) \sum_{i=0}^{\lfloor \frac{n}{2}\rfloor}\sum_{2i}^{n}1=\sum_{i=0}^{\lfloor \frac{n}{2}\rfloor}(n-2i+1) i=02n2in1=i=02n(n2i+1)
【为什么是 ⌊ n 2 ⌋ \lfloor \frac{n}{2}\rfloor 2n?当外部循环运行k次时,划线语句能运行(n+1-2k)次,而划线语句只能执行减少到一次时,下一次循环将终止,此时 n+1-2k=1,有 k = ⌊ n 2 ⌋ k=\lfloor \frac{n}{2}\rfloor k=2n
∑ i = 0 ⌊ n 2 ⌋ ( n − 2 i + 1 )   = (n+1) ( ⌊ n 2 ⌋ + 1 ) − 2 ⌊ n 2 ⌋ ( ⌊ n 2 ⌋ + 1 ) 2 = ( ⌊ n 2 ⌋ + 1 ) ( ⌊ n 2 ⌋ + 1 ) = { n是偶数: ( n 2 + 1 ) 2 n 是奇数: ( n + 3 2 ) ( n + 1 2 ) \begin{aligned}&\sum_{i=0}^{\lfloor \frac{n}{2}\rfloor}(n-2i+1)\:=\text{(n+1)}(\lfloor \frac{n}{2}\rfloor+1)-2\frac{\lfloor \frac{n}{2}\rfloor(\lfloor \frac{n}{2}\rfloor+1)}{2}\\&=(\lfloor \frac{n}{2}\rfloor+1)(\lfloor \frac{n}{2}\rfloor+1)=\begin{cases}\text{n是偶数:}(\frac{n}{2}+1)^2\\\\n\text{是奇数:}(\frac{n+3}2)(\frac{n+1}2)\end{cases}\end{aligned} i=02n(n2i+1)=(n+1)(⌊2n+1)222n(⌊2n+1)=(⌊2n+1)(⌊2n+1)= n是偶数:(2n+1)2n是奇数:(2n+3)(2n+1)
渐进时间复杂度为: O ( n 2 ) O(n^2) O(n2)

2-13

f 1 ( n ) = O ( g 1 ( n ) ) , f 2 ( n ) = O ( g 2 ( n ) ) f_1(n)=O(g_1(n)),\quad f_2(n)=O(g_2(n)) f1(n)=O(g1(n)),f2(n)=O(g2(n)), 证明下列结论成立。
(1) f 1 ( n ) + f 2 ( n ) = O ( max ⁡ { g 1 ( n ) , g 2 ( n ) } ) f_1(n)+f_2(n)=O(\max\{g_1(n),\quad g_2(n)\}) f1(n)+f2(n)=O(max{g1(n),g2(n)})

(2) f 1 ( n ) + f 2 ( n ) = O ( g 1 ( n ) − g 2 ( n ) ) f_1(n)+f_2(n)=O(g_1(n)-g_2(n)) f1(n)+f2(n)=O(g1(n)g2(n))

答案:(1)解:因为 f 1 ( n ) ∈ O ( g 1 ( n ) ) f_1(n)\in O(g_1(n)) f1(n)O(g1(n)),所以存在正常数 c 1 c_1 c1和自然数 n 1 n_1 n1,当 n ≥ n 1 n\ge n_1 nn1,有 f 1 ( n ) ≤ c 1 g 1 ( n ) f _1(n)\leq c_1 g_1(n) f1(n)c1g1(n)

因为 f 2 ( n ) ∈ O ( g 2 ( n ) ) f_2(n)\in O(g_2(n)) f2(n)O(g2(n)),所以存在正常数 c 2 c_2 c2和自然数 n 2 n_2 n2,当 n ≥ n 2 n\ge n_2 nn2,有 f 2 ( n ) ≤ c 2 g 2 ( n ) f _2(n)\leq c_2 g_2(n) f2(n)c2g2(n)
c 3 = max ⁡ { c 1 , c 2 } , n 3 = max ⁡ { n 1 , n 2 } c_3=\max\{c_1,c_2\},n_3=\max\{n_1,n_2\} c3=max{c1,c2},n3=max{n1,n2},

则当 n ≥ n 0 n\geq n_0 nn0时,有
f 1 ( n ) + f 2 ( n ) ≤ c 1 g 1 ( n ) + c 2 g 2 ( n ) ≤ c 3 g 1 ( n ) + c 3 g 2 ( n ) = c 3 ( g 1 ( n ) + g 2 ( n ) ) ≤ 2 c 3 max ⁡ { g 1 ( n ) + g 2 ( n ) } = O ( max ⁡ { g 1 ( n ) + g 2 ( n ) } ) \begin{align} f_1(n)+f_2(n)&\leq c_1g_1(n)+c_2g_2(n) \\&\leq c_3g_1(n)+c_3g_2(n)=c_3(g_{1}(n)+g_{2}(n)) \\&\leq 2c_3 \max\left \{ g_{1}(n)+g_{2}(n) \right \} \\&=O(\max\left \{ g_{1}(n)+g_{2}(n) \right \}) \end{align} f1(n)+f2(n)c1g1(n)+c2g2(n)c3g1(n)+c3g2(n)=c3(g1(n)+g2(n))2c3max{g1(n)+g2(n)}=O(max{g1(n)+g2(n)})
(2)解:因为 f 1 ( n ) = O ( g 1 ( n ) ) f_1(n)=O(g_1(n)) f1(n)=O(g1(n)),所以存在正常数 c 1 c_1 c1和自然数 n 1 n_1 n1,当 n ≥ n 1 n\ge n_1 nn1,有 f 1 ( n ) ≤ c 1 g 1 ( n ) f _1(n)\leq c_1 g_1(n) f1(n)c1g1(n)

因为 f 2 ( n ) = O ( g 2 ( n ) ) f_2(n)=O(g_2(n)) f2(n)=O(g2(n)),所以存在正常数 c 2 c_2 c2和自然数 n 2 n_2 n2,当 n ≥ n 2 n\ge n_2 nn2,有 f 2 ( n ) ≤ c 2 g 2 ( n ) f _2(n)\leq c_2 g_2(n) f2(n)c2g2(n)
c = max ⁡ { c 1 , c 2 } , n = max ⁡ { n 1 , n 2 } c=\max\{c_1,c_2\},n=\max\{n_1,n_2\} c=max{c1,c2},n=max{n1,n2},

则当 n ≥ n 0 n\geq n_0 nn0时,有
f 1 ( n ) + f 2 ( n ) ≤ c 1 g 1 ( n ) + c 2 g 2 ( n ) ≤ c g 1 ( n ) + c g 2 ( n ) = c ( g 1 ( n ) + g 2 ( n ) ) = O ( g 1 ( n ) + g 2 ( n ) ) \begin{align} f_1(n)+f_2(n)&\leq c_1g_1(n)+c_2g_2(n)\\&\leq cg_1(n)+cg_2(n)=c(g_{1}(n)+g_{2}(n))\\&=O(g_{1}(n)+g_{2}(n)) \end{align} f1(n)+f2(n)c1g1(n)+c2g2(n)cg1(n)+cg2(n)=c(g1(n)+g2(n))=O(g1(n)+g2(n))

5-8

5-8三分搜索算法的做法是: 它先将待查元素x与n/3处的元素比较,然后将x与2n/3处的元素进行比较。比较的结果或者找到x,或者将搜索范围缩小为原来的n/3。
(1) 编写c++程序实现算法;
(2) 分析算法的时间复杂度。

答:(1)

#include <iostream>
#include <cmath>
#define MAX 50
using namespace std;

int l[MAX];
int search(int left, int right, int x);
int main(){
    int i,n,x;
    cout<<"Enter the number of elements in the list: ";
    cin>>n;
    cout<<"Enter the elements of the list: ";
    for (i=0;i<n;i++)
        cin>>l[i];
    cout<<"Enter the element to be searched: ";
    cin>>x;
    i=search(0,n-1,x);
    if (i==-1)
        cout<<"Element not found"<<endl;
    else
        cout<<"Element found at position "<<i+1<<endl;

    cout << "Press any key to exit...";
    cin.ignore();
    cin.get();
    return 0;
}

int search(int left, int right, int x){
	int m1,m2;
	if (left==right) {
	if (l[left]=-x)
		return left;
	}
    if (left<right){
        m1=left+(right-left)/3;
        m2=(int)ceil((double)(right-(right-left)/3));
        if (x==l[m1]) return m1;
        else if (x<l[m1]) return search(left,m1-1,x);
        else if (x<l[m2]) return search(m1+1,m2-1,x);
        else if (x==l[m2]) return m2;
        else return search(m2+1,right,x);
    }
    else return -1;
}

运行结果:

(2)该算法是有三个分支的尾递归函数,最终只会进入到三种可能范围的其中一种中进行递归。

递推关系式是: T ( n ) = T ( 3 / n ) + 2 T(n)=T(3/n)+2 T(n)=T(3/n)+2

定理5-1:a,b,c和k为常数, T ( n ) = a T ( n / b ) + c n k T(n)=aT(n/b)+cn^k T(n)=aT(n/b)+cnk,T(1)=c,则
T ( n ) = { Θ ( n log ⁡ b a ) 如果a ≥ b k Θ ( n k log ⁡ n ) 如果a = b k Θ ( n k ) 如果a<b k T(n)=\begin{cases}\Theta({n^{\log_ba}})&\text{如果a}\geq{b^k}\\\Theta({n^k}\log{n})&\text{如果a}={b^k}&\\\Theta({n^k})&\text{如果a<b k}&\end{cases} T(n)= Θ(nlogba)Θ(nklogn)Θ(nk)如果abk如果a=bk如果a<b k
由该定理可得: T ( n ) = Θ ( log ⁡ n ) T(n)=\Theta(\log{n}) T(n)=Θ(logn)

5-9

设有对半搜索算法如下:

ResultCode SortableList<T>::Search2( T& x)const
{
    int m, left-0, right-n;
    while (left<right-1){
        m=(left+right)/2;
        if(x<l[m]) right-m; else left=m;
    }
    if(x=l[left]){
        x=l[left]; return Success;
    
    }
    return NotPresent:
}

(1)画出 n=8 的二叉判定树。

(2)证明这一算法的最好、平均和最坏情况的时间复杂度均为 Θ ( log ⁡ n ) \Theta(\log{n}) Θ(logn)

答:(1)

1

(2)因为该算法总是先经过while循环后再进行条件判断:即使是最好情况下,要寻找的元素恰好在中间,该算法依然要进入while循环。

所以 T ( n ) = T ( n / 2 ) + 1 T(n)=T(n/2)+1 T(n)=T(n/2)+1,由定理5-1可得: T ( n ) = Θ ( log ⁡ n ) T(n)=\Theta(\log{n}) T(n)=Θ(logn)

5-11

对两组数据:(1,1,1,1,1) 和 (5,5,8,3,4,3,2) 执行程序 5-12 的快速排序,按 5-1 的格式分别列表表示执行过程。

答:(1)

image-20240325205815334

(2)

image-20240325204833316

6-1

设有背包问题 n = 7 , M = 15 , ( w 0 , w 1 , … , w 6 ) = ( 2 , 3 , 5 , 7 , 1 , 4 , 1 ) n=7,M = 15,(w_0,w_1,\dots,w_6)=(2,3,5,7,1,4,1) n=7,M=15,(w0,w1,,w6)=(2,3,5,7,1,4,1),物品装入背包的收益为: ( p 0 , p 1 , … , p 6 ) = ( 10 , 5 , 15 , 7 , 6 , 18 , 3 ) (p_0,p_1,…,p_6)=(10,5,15,7,6,18,3) (p0,p1,,p6)=(10,5,15,7,6,18,3)。求这实例的最优解和最大收益。

由已知可得:
( p 0 w 0 , p 1 w 1 , ⋯   , p 6 w 6 ) = ( 10 2 , 5 3 , 15 5 , 7 7 , 6 1 , 18 4 , 3 1 ) = ( 5 , 5 3 , 3 , 1 , 6 , 9 2 , 3 ) (\frac{p_{0}}{w_{0}},\frac{p_{1}}{w_{1}},\cdots,\frac{p_{6}}{w_{6}})=(\frac{10}{2},\frac{5}{3},\frac{15}{5},\frac{7}{7},\frac{6}{1},\frac{18}{4},\frac{3}{1})=(5,\frac{5}{3},3,1,6,\frac{9}{2},3) (w0p0,w1p1,,w6p6)=(210,35,515,77,16,418,13)=(5,35,3,1,6,29,3)
所以最优解为: ( x 0 , x 1 , x 2 , x 3 , x 4 , x 5 , x 6 ) = ( 1 , 2 3 , 1 , 0 , 1 , 1 , 1 ) (x_{0},x_{1},x_{2},x_{3},x_{4},x_{5},x_{6})=(1,\frac{2}{3},1,0,1,1,1) (x0,x1,x2,x3,x4,x5,x6)=(1,32,1,0,1,1,1)

最大收益为 1 × 10 + 2 3 × 5 + 1 × 15 + 1 × 6 + 1 × 18 + 1 × 3 = 55 1 3 1\times10 + \frac{2}{3}\times5+1\times15+1\times6+1\times18+1\times3=55\frac{1}{3} 1×10+32×5+1×15+1×6+1×18+1×3=5531

6-8

设 w={3,7,8,9,15,16,18,20,23,25,28} ,请按照贪心准则,构造一棵最优3路合并树。

2

6-9

G = ( V , E ) G=(V,E) G=(V,E) 是一个无向连通图, n = ∣ V ∣ , m = ∣ E ∣ n=|V|,m=|E| n=V,m=E,且 m = m= m= 0 ( n 1.99 ) 0(n^{1.99}) 0(n1.99),试问选择何种算法求图的最小代价生成树,是普里姆算法还是克卢斯卡尔算法?

因为普里姆算法的时间复杂度为 O ( n 2 ) O(n^2) O(n2), 克鲁斯卡尔算法的时间复杂度为 O ( m l o g m ) O(m logm) O(mlogm)

因此当 m = O ( n 1.99 ) m=O(n^{1.99}) m=O(n1.99)时,此时使用克鲁斯卡尔算法的时间复杂度是 O ( n 1.99 l o g ( n 1.99 ) ≈ O ( n 2 l o g n ) O(n^{1.99} log(n^{1.99})\approx O(n^2logn) O(n1.99log(n1.99)O(n2logn),大于普里姆算法的时间复杂度。所以该情况下,普里姆算法效率较好。

  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值