期末算法分析理论复习题

目录

8-1 计算题-时间复杂度分析

8-2 动态规划法与贪心法的异同

8-3 矩阵连乘

8-4 最大子数组和

8-5 旅行商问题

8-6 算法设计题-0-1背包问题

8-7 算法设计题-活动安排

8-8 算法设计题-找零钱问题


优先队列式分枝限界法选取扩展结点的原则是( )。

A.先进先出

B.后进先出

C.结点的优先级

D.随机

答案:C

下列算法中通常以自底向上的方式求解最优解的是( )。

A.备忘录法

B.动态规划法

C.贪心法

D.回溯法

答案:B

一个问题可用动态规划法或贪心法求解的关键特征是问题的( )。

A.贪心选择性质

B.重叠子问题

C.最优子结构性质

D.定义最优解


答案:C

Dijkstra算法是利用( )实现的算法。

A.分治算法

B.动态规划算法

C.贪心算法

D.回溯法

答案:C

快速排序算法是根据( )思想设计的算法。

A.回溯法

B.动态规划法

C.分治算法

D.贪婪算法

答案:C

若分治法的时间递归式是:
T(n) = aT(n/b) + O(n^c)
那么把二分查找法看成分治法时,上述公式中的a,b,c分别是--

A.2,2,1

B.1,2,1

C.2,2,0

D.1,2,0


答案:D

装载问题是0-1背包问题的特例,原因是_____。

A.一艘船装载总重量尽量大的集装箱以后,另一艘船就可以装重量尽量少的集装箱。

B.一艘船装载总重量尽量大的集装箱以后,就可以知道另一艘船能不能装下其余的集装箱。

C.这两个问题都是以集装箱不可分割作为前提。

D.这两个问题都是尽可能装载重量更多的集装箱。


答案:B

对n皇后问题求一个可行解,若n为偶数,那么已经满足“同一行、同一列都不能有两个皇后”约束条件下的解空间大小(最精确的)是_______。

A.不超过(2n)

B.不超过(2n/2)

C.不超过(n!)

D.不超过(n!/2)

答案:D

关于分治算法描述正确的是

A.分治算法通常用于解决那些可以分解为多个相似子问题的问题。

B.归并排序不是分治算法的一种。

C.分治算法不能用来排序

D.分治算法的时间复杂度总是O(n log n)。


答案:A

某算法的时间复杂度是O(n2),表明该算法的( )。

A.问题规模是n2

B.执行时间等于n2

C.执行时间与n2成正比

D.问题规模与n2成正比


答案:C

以下答案仅代表个人想法,仅供参考 

8-1 计算题-时间复杂度分析

已知一个分治算法耗费的计算时间T(n),T(n)满足如下递归方程:

image.png

请求解此递归方程。(logn为

image.png

的简记)

解:

8-2 动态规划法与贪心法的异同

简述动态规划法与贪心法的异同。

解:

同:

贪心法和动态规划算法都要求问题具有最优子结构性质

异:

动态规划:依赖于子问题的解,自底向上或自顶向下求解

贪心法:不依赖于子问题的解,自顶向下求解

动态规划的条件:子问题的重叠性质

贪心法的条件:最优子结构性质,贪心选择性质

8-3 矩阵连乘

利用动态规划法计算矩阵连乘积A1A2A3A4A5的最佳求积顺序(即:数乘次数最少的计算次序),各矩阵的维数分别为:

image.png

(要求给出计算步骤)

解:

递推式m[i][j]=m[i][k]+m[k+1][j]+pi-1*pk*pj

m数组为第i个矩阵到第j个矩阵的最小乘法执行次数

s为断开位置即为每个式子里的k

计算顺序(((A1A2)(A3A4))A5)

执行乘法次数为1655

8-4 最大子数组和

已知由8个整数构成的序列:(12,-4,7,-5,16,-4,8,7)。

(1)请用分治法求最大子数组和(请给出分解与合并的具体步骤及子数组和);

(2)请用动态规划法求最大子数组和(请给出递推式、计算过程及最后的子数组及子数组和);

(3)请根据该题,对比分治法与动态规划法的异同(请给出不少于4个异同点)。

解:

(1)

分解步骤:

1、将序列分为两半:左区间部分为(12, -4, 7, -5),右区间部分为(16, -4, 8, 7)。

2、递归地求左区间和右区间的最大子数组和。

3、求跨越两半部分的最大子数组和。

合并步骤:

1、左区间的最大子数组和

分解为(12, -4)和(7, -5)

(12, -4)的最大子数组和为12

(7, -5)的最大子数组和为7

跨越(12, -4)和(7, -5)的最大子数组和为12 + (-4) + 7 = 15

左半部分的最大子数组和为15

2、右区间的最大子数组和

分解为(16, -4)和(8, 7)

(16, -4)的最大子数组和为16

(8, 7)的最大子数组和为15

跨越(16, -4)和(8, 7)的最大子数组和为16 + (-4) + 8 + 7 = 27

右半部分的最大子数组和为27

3、跨越两个区间的最大子数组和:

从左区间的末尾开始向左求最大子数组和:12 + (-4) + 7 + (-5) = 10

从右区间的开始向右求最大子数组和:16 + (-4) + 8 + 7 = 27

跨越两半部分的最大子数组和为10 + 27 = 37

最大子数组和为37,最大子数组为(12,-4,7,-5,16,-4,8,7)

(2)

设dp[i]表示前i个元素中的最大子数组和

递推式为

dp[0]=0

dp[i]=max(dp[i-1]+a[i],a[i])

计算过程

初始化dp[0]=0

计算dp[1] = max(dp[0] + 12, 12) = 12

计算dp[2] = max(dp[1] + (-4), -4) = 8

计算dp[3] = max(dp[2] + 7, 7) = 15

计算dp[4] = max(dp[3] + (-5), -5) = 10

计算dp[5] = max(dp[4] + 16, 16) = 26

计算dp[6] = max(dp[5] + (-4), -4) = 22

计算dp[7] = max(dp[6] + 8, 8) = 30

计算dp[8] = max(dp[7] + 7, 7) = 37

最大子数组和为37,最大子数组为(12,-4,7,-5,16,-4,8,7)

(3)

两者的共同点是将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

两者的不同点如下:

适合用动态规划法求解的问题,分解得到的各子问题往往不是相互独立的(重叠子问题性质),而分治法中的子问题相互独立;

另外,动态规划法用表保存已求解过的子问题的解,再次碰到同样的子问题时不必重新求解,只需查询答案,故可获得多项式级时间复杂度,效率较高,而分治法中对于每次出现的子问题均求解,导致同样的子问题被反复求解,故产生指数增长的时间复杂度,效率较低。

8-5 旅行商问题

用分支限界法求解旅行商问题,如图所示,n=4,城市1为售货员所在的城市,请画出最终的搜索树。
 

image.png

 解:

旅行商问题要求,从某一点开始行走,经过其他所有的点,并回到初始点的最短路径

路径上的数字为下一个走到的城市,结点上的数字为当前走过的城市所需走的距离之和

如图

搜索所有路径情况

1,2,3,4,1        距离为59

1,2,4,3,1        距离为66

1,3,2,4,1        距离为25

1,3,4,2,1        距离为66

1,4,2,3,1        距离为25

1,4,3,2,1        距离为59

最短路径为

1,3,2,4,1        距离为25

1,4,2,3,1        距离为25

8-6 算法设计题-0-1背包问题

(提示:算法设计题,要先用文字阐述算法设计思想,然后用伪代码的形式给出算法,最后要进行算法时间复杂度分析,另如果用到贪心算法,则需要分析其是否具体贪心选择性质)

0-1背包问题∶给定n种物品和一背包,物品i的重量是wi,其价值为vi,背包的容量为C.问应该如何装入背包,使得背包中物品的总价值最大?写出用回溯法解决该问题的算法。

解:

对于01背包问题使用回溯算法,每个物品有选和不选两个状态,递归搜索所有可能的情况进行搭配

对于01背包问题使用回溯算法,每个物品有选和不选两个状态,递归搜索所有可能的情况进行搭配

// 定义全局变量
定义 v[1...n], w[1...n], st[1...n], jl[1...n]
定义 n, m, res, sum, zl

函数 dfs(x)
    如果 x > n
        如果 res < sum
            设置 res = sum
            设置 zl = 0
            对于 i 从 1 到 n
                设置 jl[i] = st[i]
                如果 st[i] = 1
                    增加 zl 以 v[i]
                结束如果
            结束循环
        结束如果
        返回
    结束如果

    对于 i 从 1 到 n + 1
        如果 i = n + 1
            调用 dfs(x + 1)
            退出循环
        结束如果

        如果 st[i] = 0 且 m - v[i] >= 0
            设置 st[i] = 1
            减少 m 以 v[i]
            增加 sum 以 w[i]
            调用 dfs(x + 1)
            设置 st[i] = 0
            增加 m 以 v[i]
            减少 sum 以 w[i]
        结束如果
    结束循环
结束函数

// 从输入读取n和m的值
读取 n, m

// 读取每个物品的价值和重量
对于 i 从 1 到 n
    读取 v[i], w[i]
结束循环

// 调用深度优先搜索函数
调用 dfs(0)

// 输出选择的物品编号
对于 i 从 1 到 n
    如果 jl[i] 不等于 0
        输出 i
    结束如果
结束循环

// 输出最大价值和总重量
输出换行
输出 res, " ", zl

总共有n个物品,每个物品有选和不选两个状态,所以时间复杂度为O(2^n)

由于需要更新记录下选取的物品编号所以时间复杂度为O(n2^n)

8-7 算法设计题-活动安排

(提示:算法设计题,要先用文字阐述算法设计思想,然后用伪代码的形式给出算法,最后要进行算法时间复杂度分析,另如果用到贪心算法,则需要分析其是否具体贪心选择性质)

某体育馆有一羽毛球场出租,现在总共有10位客户申请租用此羽毛球场,每个客户所租用的开始时间和结束时间如下表所示,其中s(i)表示开始租用时间,f(i)表示结束租用时间:

image.png

同一时刻,该羽毛球场只能租给一位客户,请设计一个租用安排方案,在这10位客户里面,使得体育馆尽可能满足多位客户的需求,并算出针对上表的10个客户申请,最多可以安排几位客户申请?

解:

本题使用贪心算法,由于一次只能租给一位客户,所以需要尽早开始尽早使租用时间结束,我们需要按结束时间从小到大排序,排序后如下

排序后如下:

伪代码:

首先记录开始时间和结束时间在q数组中,q数组的数据类型为包含两个int类型的结构体

开始
    // 输入元素个数 n
    输入 n

    // 初始化结构体数组 q,用于存储每对开始时间和结束时间
    对于 i = 1 到 n
        输入 q[i].a 和 q[i].b
    结束

    // 使用快速排序进行排序
    对 q[1] 到 q[n] 进行排序

    // 初始化变量
    sum = 0
    dq = 0

    // 遍历排序后的数组 q
    对于 i = 1 到 n
        如果 i = 1
            dq = q[i].b
            sum = sum + 1
        否则如果 q[i].a >= dq
            dq = q[i].b
            sum = sum + 1
        结束如果
    结束
    
    //输出最多能安排的客户
    输出 sum
结束

由于存在排序,使用快速排序的平均时间复杂度为O(nlogn),检查客户所用的时间复杂度为O(n),所以该算法的时间复杂度为O(nlogn)

按照上述策略,我们选择了以下客户:3, 6, 7, 9,所以最多可以安排4位客户的申请。

8-8 算法设计题-找零钱问题

(提示:算法设计题,要先用文字阐述算法设计思想,然后用伪代码的形式给出算法,最后要进行算法时间复杂度分析,另如果用到贪心算法,则需要分析其是否具体贪心选择性质)

小明是一个销售员,客人在他的地方买了东西,付给了小明一定面值的钱之后,小明需要把多余的钱退给客人,客人付给了小明n,小明的东西的售价为m,小明能退回给客人的面额只能为[100,50,20,10,5,2,1]的组合,设计一种策略,使小明想要使找出去纸币张数最小。(不需要写出详细代码,只需写出使用的算法策略名称、算法策略、数据准备以及程序实现流程)

解:

算法策略名贪心算法

算法策略由于需要找出去的纸币张数最小,所以需要优先找给客人大面额的纸币

数据准备

客人付的金额n

小明商品的售价m

可以退回顾客的面额用数组sz存[100,50,20,10,5,2,1]

程序实现流程:

首先计算出需要找的金额数,面额数组已经从大到小排序好,如果没排序好需要排序,所以只需遍历一遍面额数组即可,优先取出面额大的纸币找钱

时间复杂度分析:

由于面额数组已经从大到小排序好,只需遍历一遍面额数组即可,所需的时间复杂度为O(n),其中n为面额数组的长度

伪代码:

// 定义纸币面额数组
sz = [100, 50, 20, 10, 5, 2, 1]

// 主程序开始
开始
    // 输入总金额n和支付金额m
    输入 n, m

    // 计算找零金额
    change = n - m

    // 初始化纸币数量计数器
    cnt = 0

    // 遍历纸币面额数组
    对于 i 从 0 到 6
        // 计算当前面额纸币的数量
        zs = change ÷ sz[i]

        // 从找零金额中减去当前面额纸币的总价值
        change = change - (zs × sz[i])

        // 累加纸币数量
        cnt = cnt + zs

        // 如果找零金额为0,结束循环
        如果 change = 0
            退出循环
        结束如果
    结束对于

    // 输出所需纸币的总数量
    输出 cnt
结束
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星与星熙.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值