北京工业大学算法设计与分析题库.docx
- 文档编号:4367976
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:24
- 大小:692.29KB
北京工业大学算法设计与分析题库.docx
《北京工业大学算法设计与分析题库.docx》由会员分享,可在线阅读,更多相关《北京工业大学算法设计与分析题库.docx(24页珍藏版)》请在冰豆网上搜索。
北京工业大学算法设计与分析题库
一、算法时间复杂性问题
1.试证明下面的定理:
(1)如果f(n)=O(s(n))并且g(n)=O(r(n)),则f(n)+g(n)=O(s(n)+r(n));
(2)如果f(n)=O(s(n))并且g(n)=O(r(n)),则f(n)*g(n)=O(s(n)*r(n))根据符号O的定义,存在正常数C1,C2和自然数N1,N2,使得对所有的n>=N1,f(n)<=C1s(n);对所有的n>=N2,g(n)<=C2r(n)所以f(n)+g(n)<=C1s(n)+C2r(n),f(n)*g(n)<=C1C2s(n)r(n);
令C3=max(C1,C2),C4=C1*C2;则:
f(n)+g(n)<=C3[s(n)+r(n)]=O(s(n)+r(n))
(n)*g(n)<=C4*s(n)*r(n)=O(s(n)*r(n))
2.假设某算法在输入规模为n时的计算时间为:
T(n)=3*2n,在A型计算机上实现并完成该算法的时间为t秒,现有更先进的B型计算机,其运算速度为A型计算机的64倍。
试求出若在先进的B型机上运行同一算法在则T秒内能求解输入规模为多大的问题?
某台t秒内完成的基本运算的次数=3*2^n新机器t秒内完成的基本运算的次数=64*3*2^n=2^6*3*2^n=3*2^(n+6)
设N为B型机上t秒钟能求解的问题的规模所以T=T(N)=3*2^N=3*2^(n+6)则:
N=n+6
3.试说明为什么“在现代计算机上运行指数(如2n)时间算法是不可能的,要想在顺序处理机上扩大所处理问题的规模,有效的途径是降低算法计算复杂度的数量级,而不是提高计算机的速度”。
一个计算时间为Ο
(1)的算法,它的基本运算执行的次数是固定的,因此,总的时间由一个常数(即,零次多项式)来限界,而一个时间为Ο(n2)的算法则由一个二次多项式来限界。
以下六种计算时间的多项式时间算法是最为常见的,其关系为
指数时间算法一般有Ο(2n)、Ο(n!
)和Ο(nn)等。
其关系为:
其中,最常见的是时间为Ο(2n)的算法。
当n取得很大时,指数时间算法和多项式时间算法在所需时间上非常悬殊因为根本就找不到一个这样的m,使得2n囿界于n^m。
换言之,对于任意的m≥0,总可以找到n0,当n≥n0时,有2n>nm。
因此,只要有人能将现有指数时间算法中的任何一个算法简化为多项式时间算法,那就取得了一个伟大的成就。
Ο(log2n)、Ο(n)和Ο(nlog2n)比另外三种时间函数的增长率慢得多。
~由这些结果可看出,当数据集的规模(即n的取值)很大时,要在现代计算机上运行具有比Ο(nlog2n)复杂度还高的算法往往是很困难的。
尤其是指数时间算法,它只有在n值取得非常小时才实用。
尽管通过提高计算机的速度比之前快1000倍,甚至10000倍,但当指数规模的n足够大时,n每增加1,1000倍的提速即可瞬间化为乌有,所以要想在顺序处理机上扩大所处理问题的规模,有效的途径是降低算法的计算复杂度的数量级,而不是提高计算机的速度。
二、简答
1.对计算复杂性的研究能够使人们弄清所求解问题的固有难度,并得出评价某类算法优劣的准则,用以指导设计出更高效的算法。
试用简短的语言说明“建立一个问题复杂性的下界要比确定它的上界困难得多!
”其复杂性上界是已知求解该问题的最快算法的费用,而复杂性下界只能通过理论证明来建立。
寻求某个问题的计算复杂性上界,只要研究一个算法的复杂性即可。
但是要寻求同一问题的计算复杂性下界,则必须考察所有的解决该问题的算法,证明一个问题的复杂性下界就需要证明不存在任何复杂性低于下界的算法。
显然,建立下界要比确定上界困难得多。
2.满足何种性质的问题被称为NP完全问题?
请简述研究NP完全问题的意义;
(1)NP即是多项式复杂程度的非确定性问题。
而如果任何一个NP问题都能通过一个多项式时间算法转换为某个NP问题,那么这个NP问题就称为NP完全问题。
如果一个NP完全问题能在多项式时间内得到解决,那么NP中的每一个问题都可以在多项式时间内解决。
(2)NP完全是指这样一类NP问题,所有的NP问题都可以用多项式时间划归到他们中的一个.所以显然NP完全的问题具有如下性质:
它可以在多项式时间内求解,当且仅当所有的其他的NP-完全问题也可以在多项式时间内求解。
这样一来,只要我们找到一个NPC问题的多项式解,所有的NP问题都可以多项式时间内划归成这个NPC问题,再用多项式时间解决,这样NP就等于P了.NP完全性理论的重要性:
知道一个问题是NP完全的就给我们提供了有价值的信息,告诉我们采用什么样的途径可以是最富有成效的。
一定不要去优先寻找有效的、精确的算法。
现在比较适当的途径是集中精力致力于其他较低目标的方法。
例如,你可以寻找解决这个问题的各种特殊情况的有效算法。
寻找在大多数情况下看来能快速运算的算法,虽然不能保证它在任何情况下都能快速地运算。
或者你甚至可以放松问题的某些方面,寻找一个只能给出满足大部分要求的快速算法。
简言之,NP完全性理论的初步应用是帮助算法设计人员找到最有可能得到有用的算法的努力方向
3.“当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质”。
问题的最优子结构性质是该问题可用动态规划算法求解的基本要素,试简要阐述“论证某一问题的最优子结构性质”时的一般方法;矩阵连乘计算次序问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质。
在分析问题的最优子结构性质时,所用的方法具有普遍性:
首先假设由问题的最优解导出的子问题的解不是最优的,然后再设法说明在这个假设下可构造出比原问题最优解更好的解,从而导致矛盾。
利用问题的最优子结构性质,以自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。
最优子结构是问题能用动态规划算法求解的前提。
同一个问题可以有多种方式刻划它的最优子结构,有些表示方法的求解速度更快(空间占用小,问题的维度低)例如:
假设(y1,y2,…,yn)是0-1背包问题的一个最优解,而(y2,…,yn)是相应子问题的一个最优解,有
假设(y2,…,yn)不是一个最优解,而(z2,…,zn)是最优解,由此可知,
这说明(y1,z1,z2,…,zn)是问题的整体最优解,与(y1,y2,…,yn)是最优解矛盾,所以证明了最优子结构性质!
三、算法设计与分析问题1.最大值和最小值问题的最优算法(18)
给定n个实数存放于一维数组A中,试设计一个算法在最坏情况下用3n/2-2次的比较找出A中的最大值和最小值(为简化,可假设n为偶数)。
2.社会名流问题
在n个人中,一个被所有人知道但却不知道别人的人,被定义为社会名流。
现在的问题是如果存在,试找出该社会名流。
你可以使用的唯一方式是询问:
“对不起,请问你知道那个人吗?
”(假定所有回答都正确,甚至这位社会名流也将回答。
)我们的最终目标是将询问的数目最小化。
给定一个n×n邻接矩阵,确定是否存在一个i,其满足在第i列所有项(除了第ii项)都为1,并且第i行所有项(除了第ii项)都为0。
大致的算法思路:
随便取一个非对角线元素比如Array[i][j],如果Array[i][j]=0成立,则j不是社会名流,于是删去第j行和第j列。
同样,如果Array[i][j]=1成立,则删去第i行和第i列;总之,无论对应项取何值,都可以删去一行和一列,因此整个操作只耗费O(n)的时间。
重复此操作直至剩下最后一个元素。
最后,检验该元素是否为社会名流即可。
如果该元素不是,则该群人中不存在社会名流。
3.数列极差问题
在黑板上写了N个正数组成的一个数列,进行如下的操作:
每一次任选其中的两个数设为a和b,将其擦去,然后在数列中加入一个新的数a*b+1,如此下去直至黑板上只剩下一个数为止。
在所有按这种操作方式最后得到的数中,最大的数记为Max,最小的数记为Min,则该数列的极差定义为M=Max-Min。
贪心算法最重要的两个性质是:
贪心选择性质和最优子结构性质。
贪心选择性质是所求问题的整体最优解可以通过一系列局部最优的选择,也就是贪心选择来达到。
而最优子结构性质是指一个问题的最优解包含其子问题的最优解。
问题的关键就是MAXMIN值的求解问题,所以首先看下怎么样来求MAXMIN值。
设有三个数xyz,且x num1=(x*y+1)*z+1=xyz+z+1,num2=(x*z+1)*y+1=xyz+y+1,num3=(y*z+1)*x+1=xyz+x+1。 很容易看出num1>num2>num3。 所以我们可以得出结论: 优先选择数列中最小的2个数进行(a*b+1)运算得到的值大,优先选择数列中最大的2个数进行(a*b+1)运算得到的值小。 我们可以把整体的MAX,MIN值通过一系列局部求MAX,MIN值来求我们想要的结果。 我们再看下用贪心策略求解的合理性: 假设经(N-3)次运算后得到3个数: xymax(max>x>y),其中max是(N-2)个数经(N-3)次运算后所得的最大值,此时最大值m=(x*y+1)×max+1。 若经(N-2)次变换后所得的3个数为: xyz(z>x>y)且z不为(N-2)次变换后的最大值,即z<max则所求得的最大值为: m’=(x*y+1)*z+1,此时m-m’=(1+x*y)(max-z)>0所以此时不为最优解。 所以若使第k(1≤k≤N-1)次变换后所得值最大,必使(k-1)次变换后所得值最大(符合贪心策略的最优子结构性质),在进行第k次变换时,只需取在进行(k-1)次变换后所得数列中的两最小数x,y进行运算,再把结果插入到数列即可。 所以综上所述: 该算法可以简单的描述为: MAX: 不断地取当前黑板上的两个最小的数进行运算并且放回,会使最后的结果最大。 MIN: 不断地取当前黑板上的两个最大的数进行运算并且放回,会使最后的结果最小。 数列极差就是: MAX-MIN! 算法设计: 先将数列a[n]按从小到大进行排列(快速排序) 进行最大值的计算: 选出a[n]中最小的两个数进行(a*b+1)运算,在把运算结果按从小到大插入到数列中。 一直这样运算,最后就可以得出MAX值。 进行最小值的计算: 选出a[n]中最大的两个数进行(a*b+1)运算,在把运算结果按从小到大插入到数列中。 一直这样运算,最后就可以得出MIN值。 最后该数列的极差M=MAX-MIN 4.试说明如何修改快速排序算法,使它在最坏情况下的计算时间为O(nlgn)。 可以通过减少递归栈的使用进行优化,快速排序的实现需要消耗递归栈的空间,而大多数情况下都会通过使用系统递归栈来完成递归求解。 对系统栈的频繁存取会影响到排序的效率。 在数据量较大时,快速排序的复杂度为O(nlgn)。 当数据集较小时,快排的复杂度有向O(n^2)发展的趋势,此时不必继续递归调用快速排序算法,使用插入排序代替快速排序。 STL中sort就是用的快排+插入排序的,使得最坏情况下的时间复杂度也是O(nlgn).这一改进被证明比持续使用快速排序算法要有效的多。 使用一个快速排序的迭代模型可以使原递归算法所需的栈空间总量减至O(logn)。 试设计这一迭代模型(算法)。 structnode {intlow,high;}st[10000]; voidquicksort2(intdata[],ints,intt){ inttop=-1,low,high;top++;st[top].low=s;st[top].high=t; while(top>-1){low=st[top].low;high=st[top].high;top--;intw; if(low st[++top].low=low;st[top].high=w-1;st[++top].low=w+1;st[top].high=high;}} 5.试设计一个构造连通图G生成树的算法,使得构造出的生成树的边的最大权值达到最小。 解答: 可以证明,图G的最小生成树即为满足题意的生成树。 假设T,T’分别为图G的最小生成树及边的最大权值达到最小值的生成树。 v,v’分别为它们的最大权边。 假如w(v)>w(v’),则将v从T删除之后,T变为两个连同的分支,此时,一定有T’的边v1连同这两个分支,否则T’将是不连通的。 从而将v1加入到T中构成一新的生成树T’’=T-v+v1。 且有w(v1) 这与T为最小生成树矛盾。 证毕。 据此利用prim算法或者Kruskal算法算得G的最小生成树即可 Prim算法O(n2) 首先置S={1},然后,只要S是V的真子集,就作如下的贪心选择: 选取满足条件i∈S,j∈V-S,且c[i][j]最小的边,将顶点j添加到S中。 这个过程一直进行到S=V时为止。 在这个过程中选取到的所有边恰好构成G的一棵最小生成树。 在上述Prim算法中,还应当考虑如何有效地找出满足条件i∈S,j∈V-S,且权c[i][j]最小的边(i,j)。 实现这个目的的较简单的办法是设置2个数组closest和lowcost。 在Prim算法执行过程中,先找出V-S中使lowcost值最小的顶点j,然后根据数组closest选取边(j,closest[j]),最后将j添加到S中,并对closest和lowcost作必要的修改。 Kruskal算法O(eloge) 首先将G的n个顶点看成n个孤立的连通分支。 将所有的边按权从小到大排序。 然后从第一条边开始,依边权递增的顺序查看每一条边,并按下述方法连接2个不同的连通分支: 当查看到第k条边(v,w)时,如果端点v和w分别是当前2个不同的连通分支T1和T2中的顶点时,就用边(v,w)将T1和T2连接成一个连通分支,然后继续查看第k+1条边;如果端点v和w在当前的同一个连通分支中,就直接再查看第k+1条边。 这个过程一直进行到只剩下一个连通分支时为止。 6.试设计在O(n)时间内求得数组A[1..n]的中位数的算法。 将n个输入元素划分成n/5(上取整)个组,每组5个元素,只可能有一个组不是5个元素。 用任意一种排序算法,将每组中的元素排好序,并取出每组的中位数,共n/5(上取整)个。 找出这n/5(上取整)个元素的中位数。 如果n/5(上取整)是偶数,就找它的2个中位数中较大的一个。 7.两个数组找第k小元素 事件复杂度O(log(k))在网上看的,和同学商讨过,可行,认为此方法比上个log(m)+log(n)的方法要好第一个数组m个元素第二个数组n个元素分别从两个数组找第k/2个数,a[k/2],b[k/2];假设a[k/2] 因为a[k/2] 其他情况同理; 当m或n小于k/2时,假设m 这样每次k都减半,直到k等于1时,从比较两个数组头中比较小的就是所求。 行运算,再把结果插入到数列即可。 【例题3】聪明的学生(题目来源: CTSC2001Clever命题人: 张力) 一个教授逻辑学的教授有三名非常善长推理且精于心算的学生A,B和C。 有一天,教授给他们三人出了一道题: 教授在每个人脑门上贴了一张纸条并告诉他们,每个人的纸条上都写了一个正整数,且某两个数的和等于第三个。 于是,每个学生都能看见贴在另外两个同学头上的整数,但却看不见自己的数。 这时,教授先对学生A发问了: “你能猜出自己的数吗? ”A回答: “不能。 ”教授又转身问学生B: “你能猜出自己的数吗? ”B想了想,也回答: “不能。 ”教授再问学生C同样的问题,C思考了片刻后,摇了摇头: “不能。 ”接着,教授又重新问A同样的问题,再问B和C,……经过若干轮的提问之后,当教授再次询问某个人时,此人突然露出了得意个笑容,在把自己头上的那个数准确无误的报了出来。 现在,如果告诉你: 教授在第N次提问时,轮到回答问题的那个人猜出了贴在自己头上的数是M,你能推断出另外两个学生的头上贴的是什么数吗? 提示: 总是头上贴着最大的那个数的人最先猜出自己头上的数。 由题意可知,每个人推断的依据仅仅是另外两个人的头上数,以及大家对教授提问所做出的否定回答,因此,找出他们推理的过程就成为解决本题的关键。 由于三个正整数中,一定有某个数是另外两个数的和,因此,当一个学生看到另两个学生头上的数时,他就知道自己的数只有两种可能,另两个数的和或差;而要猜出自己头上的数,只需否定两种可能中的一种,那另一种就是答案了。 因为三个数都是正整数,所以,若某个学生看到另两个学生的数相等,那他立刻就可以判断自己的数是另外两个数的和(因为不可能是0),相反,若他猜不出来,则给了另两个人一个信息——自己的数和第三个人的数不同,而这可以成为做出推理的一个重要条件。 为了把问题说得更加清楚,不妨举个例子来说: 当N=5,M=8时,有一个可能的情况是A、B、C三个人头上贴的数分别为2,8,6。 B为什么能在第5次提问——即第2次问到他时——猜出自己的数呢? 他是这样想的: “我看到的是A的2和C的6,因此,我头上的数只可能是4(=6-2)或8(=2+6)。 但假如我的数是4,那在教授的第3次提问时,C就能猜出自己的数来! ——因为那时他看到的是A的2和我的4,C就面临着2(=4-2)和6(=2+4)的选择,但假如他是2,那在教授第2次提问时,我就能猜出来,因为我看到的是两个2! 因此他能肯定自己不是2,而是6。 ——而实际上C并未猜出,因此,我头上的数必定是8! ” B的推理过程实际上是一个“假设——排除”的过程,即使设自己的数为两个数可能数中一个,如果另两个人中有人可以在自己之前猜出,那么被假设的那种情况就可以排除,从而也就猜出了自己的数。 而原题中又给我们提示: “总是头上贴着最大的那个数的人最先猜出自己头上的数”,因此只需要排除另两个数的差的那种情况就可以了。 现在,实际上已经可以解决这样一个问题: 已知A,B,C三人头上贴的数为X1,X2,X3,求教授至少需要提问多少次,轮到回答问题的那个人才能猜出自己的数。 再来分析一下这个问题。 由原题提示中的结论“总是头上贴着最大的那个数的人最先猜出自己头上的数”,于当X1,X2,X3给出之后,谁最先猜出就已经确定了。 不妨设最终猜出的人是B,那么既有X1+X3=X2,而B做出判断的依据即是排除了X2=│X1-X3│的可能,而他能够排除这种可能的依据则是X1=X3,假设X2=│X1-X3│的前提下,在前两个提问时,A或C必定能够猜出自己的数,而实际上他们没有猜出——即当前教授提问的次数,已经大于当三个人头上的数分别为X1,│X1-X3│,X3时,直到某人猜出自己的数为止教授需要提问的次数,这样B就能确定自己的数。 而对于X1,│X1-X3│,X3时求提问次数,就又变成了一个子问题,在这个情况下,最先猜出自己的数的人即为A或C(这取决与X1与X3)的大小,若X1>X3,则A先猜出,否则就是C先猜出),这样就又安装上面的思路求解。 这显然就是一个递归求解的过程。 设函数Times(i,j,t1,t2,t3)表示编号为t1①的人头上的数为i,编号为t2的人的数为j,编号为t3的人的数为i+j(即由t3最先猜出自己的数)时,教授需要提问的次数;P(t1,t2)表示教授按照1-2-3的顺序,从t1问到t2,最少需要提问的次数②,则根据上面的分析,有如下关系: t3,i=j times(i,j,t1,t2,t3)= times(i,j-i,t1,t3,t2)+P(t2,t3),i 于是,根据这一递归函数即可解决上面提出的问题。 当然,前面解决的问题和原题还有不同,原题已知N,M要求三人头上的数,而刚解决的问题是已知三人头上的数,要求N,M——恰好将问题与条件互换了。 那么如何利用已有的结论来解决原来的问题呢? 很简单——用枚举法(还记得前面强调过的么? 枚举可以为其他算法创造条件)! 由于M是三个数中最大的,则另两数只能在区间[1,M-1]内,又因为有这两数之和等于M,因此,只需枚举其中一个i,另一个就可以由M-i求出。 对于枚举的每一种情况,判断其相应的Times函数值是否等于N,若等于,则为问题的一个解。 至此,本题已经获圆满解决。 ①为了叙述方便,特将A,B,C三人编号为1,2,3,下同 ②实际上,当t2>t1时,P(t1,t2)=t2-t1,否则,P(t1,t2)=t2+3-t1 寻找丢失的数! 类C语言: 用一个二维数组保存数组中的数的二进制位,然后从右往左按列扫描,然后确定之后删除被排除的行和,然后扫描第二次。 特殊的整理: 桶排序: 桶排序工作的原理是: 将阵列分到有限数量的桶子里。 每个桶子再个别排序。 当要被排序的阵列内的数值是均匀分配的时候,桶排序使用线性时间(Θ(n))。 要对大小为[1..1000]范围内的n个整数A[1..n]排序,可以把桶设为大小为10的范围,具体而言,设集合B[1]存储[1..10]的整数,集合B[2]存储(10..20]的整数,……集合B[i]存储((i-1)*10,i*10]的整数,i=1,2,..100。 总共有100个桶。 然后对A[1..n]从头到尾扫描一遍,把每个A[i]放入对应的桶B[j]中。 然后再对这100个桶中每个桶里的数字排序,这时可用冒泡,选择,乃至快排,一般来说任何排序法都可以。 最后依次输出每个桶里面的数字,且每个桶中的数字从小到大输出,这样就得到所有数字排好序的一个序列了。 假设有n个数字,有m个桶,如果数字是平均分布的,则每个桶里面平均有n/m个数字。 如果对每个桶中的数字采用快速排序,那么整个算法的复杂度是O(n+m*n/m*log(n/m))=O(n+nlogn-nlogm) 从上式看出,当m接近n的时候,桶排序复杂度接近O(n)。 简答题: 贪心和动态规划的区别! 主要理解贪心的思想局部! 所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。 这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。 动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。 对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。 贪心算法和动态规划算法都要求问题具有最优子结构性质,这是2类算法的一个共同点。 雏形整理第一章和第二章: 算法特性: 有穷,可行,确定,输入,输出四元组(Q,I,,f)时间复杂性的定义掌握,理解上界,下界和精确界的证明过程,已经背下来了,分为多项式时间算法和指数时间算法;O (1) ) 买鸡问题: voidchicken_problem(intn,int&k,intg[],intm[],ints[]){inti,j,a,b,c;k=0;i=n/5;j=n/3;for(a=0;a<=i
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 北京工业大学 算法 设计 分析 题库