算法复习

 

什么是基本运算?

答:基本运算是解决问题时占支配地位的运算(一般1种,偶尔两种);讨论一个算法优劣时,只讨论基本运算的执行次数。

什么是算法的时间复杂性(度)?

答:算法的时间复杂性(度)是指用输入规模的某个函数来表示算法的基本运算量。T(n)=4n3

什么是算法的渐近时间复杂性?

答:当输入规模趋向于极限情形时(相当大)的时间复杂性。

表示渐进时间复杂性的三个记号的具体定义是什么? 

答:1. T(n)= O(f(n)):若存在c > 0,和正整数n0≥1,使得当n≥n0时, 总有 T(n)≤c*f(n)。 (给出了算法时间复杂度的上界,不可能比c*f(n)更大)

   2. T(n)=Ω(f(n)):若存在c > 0,和正整数n0≥1,使得当n≥n0时, 存在无穷多个n ,使得T(n)≥c*f(n)成立。(给出了算法时间复杂度的下界,复杂度不可能比c*f(n)更小)

   3. T(n)= Θ(f(n)):若存在c1,c2>0,和正整数n0≥1,使得当n≥n0时, 总有 T(n)≤c1*f(n),   且有无穷多个n,使得T(n)≥c2*f(n)成立, 即:T(n)= O(f(n))与T(n)=Ω(f(n))都成立。(既给出了算法时间复杂度的上界,也给出了下界)

什么是最坏情况时间复杂性?什么是平均情况时间复杂性?

答:最坏情况时间复杂性是规模为n的所有输入中,基本运算执行次数为最多的时间复杂性。

   平均情况时间复杂性是规模为n的所有输入的算法时间复杂度的平均值 (一般均假设每种输入情况以等概率出现)。

一般认为什么是算法?什么是计算过程?

答:一般认为,算法是由若干条指令组成的有穷序列,有五个特性a.确定性(无二义)b.能行性(每条指令能够执行)c.输入 d.输出 e.有穷性(每条指令执行的次数有穷)

只满足前4条而不满足第5条的有穷指令序列通常称之为计算过程。

算法研究有哪几个主要步骤?主要从哪几个方面评价算法?

答:算法研究的主要步骤是1)设计2)表示 3)确认,合法输入和不合法输入的处理 4)分

析 5)测试

   评价算法的标准有1)正确性 2)健壮性 3)简单性 4)高效性 5)最优性

关于多项式时间与指数时间有什么样的结论?

答:1. 多项式时间的算法互相之间虽有差距,一般可以接受。 

    2. 指数量级时间的算法对于较大的n无实用价值。 

什么是相互独立的函数序列?何时称函数项μk(x)能被其它函数项线性表出?

答:设{μ0(x), μ1(x), μ2(x), ⋯ ,μn(x), ⋯}是某一数域上的函数序列, (x的值以及μk(x)(k=0,1,2, ⋯)的值都在同一个数域中) 任取μk(x)(k=0,1,2, ⋯),不存在数域中的数α1,α2,⋯,αp,使得μk (x) = α1μi1(x) + α2μi2 (x) + ⋯ + αpμip (x) ,即任何一个函数项μk(x)不能被其它函数项线性表出。

根据特征根的情况,常系数线性递归方程的解有哪几种不同的形式?

答:1.若方程(**)恰有r个互不相同的特征根α1,α2,⋯,αr (即i≠j时有αi≠αj),则齐次方程(*)的解为 an=A1+ A2+ ⋯+Ar(齐通解,即齐次方程的通解) (A1~Ar为待定系数,可由r个连续的边界条件唯一确定) 

2.若α1,α2是(**)方程的一对共扼复数根ρ和ρ, eiθeiθ.则这两个根对应的解的部分为Aρncos(nθ)+Bρnsin(nθ) (A,B为实的待定系数)

3.若α是(**)方程的k重根,则α对应的解的部分为 C1αn+ C2 nαn+ C3 n2αn+ ⋯+Ck nk-1αn (C1~Ck为待定常数)

4.若(*)方程中的f(n)≠0(非齐次),且q(n)是(*)的一个解, 则(*)方程的解为: (*)的齐通解(含有待定系数)+ q(n) (非齐特解), (齐通解中的待定系数由边界条件唯一确定)

求和中的通项与积分中的被积函数之间有什么样的关系?

答:求和中的通项的表达形式一般就是被积函数,一般用放缩的方法求得通项得上下界。

主定理的内容是什么?根据主定理的结论,可以获得哪些关于算法改进的启示?

答:T(n)=a*T(n/b)+f(n) 

1)    若有ε> 0, 使f(n)=O() (即f(n)的量级多项式地小于的量级), 则T(n)= Θ ()。 

2)    若f(n)= Θ() (即f(n)的量级等于的量级), 则T(n) =Θ()。 

3)    若f(n)= Θ(), 则T(n)=Θ( )

3) 若有ε>0, 使f(n)=Ω() ε+)(aLogbn(即f(n)的量级多项式地大于的量级), 且满足正规性条件: abLogn存在常数c<1, 使得对所有足够大的n,有a*f(n/b)≤c*f(n), 则T(n)=Θ(f(n))。

   正规性条件的直观含义: 对所有足够大的n,a个子问题的分解准备与再综合所需要的 时间总和,严格小于原问题的分解准备和综合所需要的时间。 因此一般来说,对于时间复杂度满足递归关系 T(n)=a*T(n/b)+f(n)的算法,只需比较f(n)与的量级大小, aLogbn算法的时间复杂度总是与量级大的那个相同(即小的那个可以忽略);若f(n)与的量级相同(或只差), aLogbnnLogk则算法的时间复杂度为f(n)*。

主定理对于算法改进得启示在于:

1)当T(n)= Θ ()时,即当的量级高于f(n)的量级时,n的量级在算法的时间复杂度中起主导作用。因而此时首先应当考虑使 aLogbnaLogbnaLogb logb a的值变小,而暂时无须考虑如何改善f(n),即此时要考虑减小a (子问题个数)且使b不变(n/b为子问题规模),或增大b(减小子问题规模)而使a不变。也就是说,此时的重点应考虑改进子问题的分解方法,暂不必考虑改进子问题组合时的处理。

2)当f(n)的量级高于或等于的量级时,则f(n)的量级在算法的时间复杂度中起主导作用。因而此时首先应当考虑把f(n)的量级往下降,即此时应着重改善子问题组合时的处理方法,减少该部分工作的处理时间f(n)。

分治法的要领是什么?(分治法可分为哪三个主要步骤?)

答:分治法的要领 

分治法是把一个规模较大的问题分解为若干个规模较小的子问题,这些子问题相互独立且与原问题同类; 首先求出这些子问题的解,然后把这些子问题的解组合起来得到原问题的解。由于子问题与原问题是同类的,故使用分治法很自然地要用到递归。

因此分治法分三步: 

1 将原问题分解为子问题(Divide) 

2 求解子问题(Conquer) 

3 组合子问题的解得到原问题的解(Combine) 

分治法求最大、最小元算法的主要思想?

答:当n=2时,一次比较就可以找出两个数据元素的最大元和最小元。 当n>2时,可以把n个数据元素分为大致相等的两半, 一半有n/2个数据元素,而另一半有n/2个数据元素。 先分别找出各自组中的最大元和最小元,然后 将两个最大元进行比较,就可得n个元素的最大元; 将两个最小元进行比较,就可得n个元素的最小元。

求最大、最小元算法的时间复杂度(比较次数)下界是多少?分治算法在什么情况下可以达到下界?

答:在规模为n的数据元素集合中找出最大元和最小元, 至少需要3n/2-2次比较,即3n/2-2是找最大最小元算法的下界。当n=2k,或当n≠2k时,若n是若干2的整数幂之和,(e.g. 42=32+8+2), 

则算法的时间复杂度仍可达到3n/2-2。

如何用分治法求两个n位二进制数x和y的乘积?算法的时间复杂度是多少?

答:若n=2k,则x可表为a2n/2+b,y可表为c2n/2+d (如图), 其中a, b, c, d均为n/2位二进制数。 于是x*y= (a2n/2+b) (c2n/2+d) = ac2n + (ad+bc)2n/2 + bd,计算式ac2n + (ad+bc)2n/2 + bd中的ad+bc可写为: 而(ad+bc)= (a+b) (d+c) - ac - bd, 因此在ac和bd计算出之后, 只要再做4次加减法,一次(n/2位数的)乘法就可以计算出ad+bc。 而原来计算(ad+bc)需要做2次乘法、一次加法; 新的计算公式比原方法少做了一次乘法。T(n)=3T(n/2) + Θ(n),即a=3, b=2, f(n)=Θ(n)。 此时有:= = naLogbn32Logn1.59,并仍有f(n)=O(), ε−)(aLogbn于是有T(n)= Θ(n1.59),比Θ(n2)要好不少。

用200字概括Select(求第k小元)算法的主要思路。

答:1.若S<50,则采用堆排序的方法找出第k小的元素

2.将n个元素分成[n/5]组,每组5个元素

3.对每个5元组进行排序,全部5元组排序后,从每组中取出第3个元素(中间元)得到一个长为[n/5]的数组M

    4.递归调用Select([|M|/2],M),即在M数组中找到第[|M|/2]小的数(中位数),记为m

    5.依次扫描整个数组S,此项工作所需时间为O(n)。 

当si<m时将si放入数组S1; 

当si=m时将si放入数组S2; 

当si>m时将si放入数组S3; 

在得到的3个集合中,S1中的数均小于m; 

S2中的数均等于m;S3中的数均大于m。

    6. 按照k值大小,共可分成下列三种情况(注意S2至少有一个元素m): k≤|S1|;|S1|<k≤|S1|+|S2|;以及k>|S1|+|S2|。 下面针对这三种情况分别进行讨论。 

6.a:若k≤|S1|,则第k小元素必定在S1中。 此时递归调用Select(k,S1),就可以获得第k小元素。 因大于等于m的数据元素至少有3n/10-6个, 而S1中的数均小于m,故S1中的数据元素至多有7n/10+6个, 即|S1|≤7n/10+6。因此,调用Select(k,S1)的 时间复杂度不超过T(7n/10+6)。

     6.b:若|S1|<k≤|S1|+|S2|,则第k小元素必定在S2中。 因为S2中的元素的值均等于m,故第k小元素就是m。 由于答案已经得到,此时立刻返回第k小元素m。 这部分工作的时间复杂度为O(1)。 

6.c:若k>|S1|+|S2|,则第k小元素必定大于m,因此在S3中。 而且此时该元素在S3中应为第k-|S1|-|S2|小的元素。 于是递归调用Select(k-|S1|-|S2|, S3), 就可以获得S中的第k小元素。 因小于等于m的数据元素至少有3n/10-6个

时间复杂度为T(n)=T(p*n)+T(q*n)+a*n时,在p+q1及p+q1的情况下,T(n)分别为什么?

答:T(n)≤a*n*∑k=0∞(p+q)k

矩阵相乘算法目前最好的时间复杂度是多少?

答:目前矩阵乘法最好的时间复杂度是能做到O(n2.376)

叙述Strassen矩阵相乘算法的主要思路和意义。

答:把矩阵A,B分成4个规模为n/2的子矩阵快

C11=A11B11+A12B21, C12=A11B12+A12

C21=A21B11+A22B21, C22=A21B12+A22B22

同时引入下列Mi(i=1,2...7)

   则计算两个n阶矩阵的乘法为7对n/2阶矩阵的乘法(时间为7T(n/2)),以及18对n/2阶矩阵的加减法则递归方程为T(n)=7T(n/2)+ Θ(n2),由主定理得T(n)= Θ(n2.81). Strassen矩阵相乘算法意义在于打破了人们认为矩阵乘法得时间复杂度为Θ(n3)得固定看法。

试用200~300字概述寻找最近点对算法的主要步骤。该算法中有哪几点最为关键?该算法是否可改进?

答:主程序算法: 

读入n个点的坐标,这n个点的x坐标和y坐标 分别放在X,Y两个数组中,然后进行预处理: 对X数组中的n个x坐标值按从小到大的次序进行排序, 排序过程中保持x坐标和y坐标的对应关系:

若X[i]与X[j]对换位置,则Y[i]与Y[j]也做相同的对换。 另外,若两个点的x坐标相同,则y坐标值小的排前。 X数组排好之后就固定了,以后不再改变, 以便在O(1)时间对其实现分拆。(排序时间为Θ(n log n)) 将数组IND初始化为:IND[i]=i(i=1,2,┉,n)。 数组IND即是用来保持x坐标和y坐标的对应关系的机制, IND[i]记录的是 其y坐标值为Y[i]的点所对应的x坐标在X数组中的下标。 对Y数组中的n个y坐标值按从小到大的次序进行排序, 排序过程中保持y坐标和x坐标的对应关系: 若Y[i]与Y[j]对换位置,则IND [i]与IND [j]也做相同的对换。 这样,当给了一个点的y坐标Y[i]之后, 就可以在O(1)时间找到其对应的x坐标: Y[i]与X[IND [i]]就是该点的y坐标和x坐标。

 调用子程序FCPP(1,n,X,Y,IND,δ,p,q) 就可求得n个点中的最近点对(p,q)和最小距离δ。 子程序FCPP的主要执行过程: 首先看当前处理的点数。若不超过3个点,就直接进行相互比较。 若超过3个点,则把点的y坐标分为两部分:左边和右边。

然后进行分治,求得两边的δL和δR,从而求得δ。 求出分割线,扫描当前的所有点,把落到2δ带状区域内的点找出来, 并使这些点的y坐标仍然保持从小到大的次序。 对落到2δ带状区域内的每一个点检查其后面的7个点, 若有距离更近的点对,则把最小距离δ(及最近点对(p,q))更新, 执行完毕时,最小距离δ及最近点对(p,q)就得到了。

子程序FCPP(j,k,X,Ypres,INDpres,δ,p,q)中的参数说明: X数组存放已排好序的n个点的x坐标。 j,k为当前处理的X数组一段中的最小和最大下标。 Ypres数组存放当前处理的k-j+1个点的y坐标 (已按从小到大的次序排好)。 INDpres数组的长度也是k-j+1,INDpres[i]记录了其y坐标值 为Ypres [i]的点的x坐标在X数组中的下标值。 δ,p,q均为返回值, 给出当前处理的k-j+1个点中的最小距离δ和最近点对(p,q)。

算法中的几个关键点:分割线的寻找和最小距离相关的比较次数的判定

算法可以优化:比如对p点之后的7个点检查时未考虑两点均属同一侧的情况可以考虑减小比较次数。

做DFT时,是否总假定有n=2m?

答:是个,总有n=2m

什么是快速傅立叶变换(FFT)?如何用FFT来计算2个多项式的乘积?

答: 能在Θ(nlogn)时间里完成DFT的算法就称为FFT.

给了2个多项式的系数向量a和b之后,若其系数不是2的幂次,则将a和b的规模扩大(向量最后加若干个0)使得n=2m..然后把这两个向量维数再扩大一倍,得到两个维数为2n的向量。分别对2个向量做DFT,所得到两个向量进行点乘,再对结果做2n阶的DFT-1,即可求得2多项式相乘后的多项式系数c

什么是平衡?分治法与平衡有着什么样的关系?

答:在使用分治法和递归时,要尽量把问题分成规模相等,或至少是规模相近的子问题,这样才能提高算法的效率。使子问题规模尽量接近的做法,就是所谓的平衡。

分治法与动态规划法之间的相同点是什么?不同之处在哪些方面?

答:与分治法类似,动态规划法 也是把问题一层一层地分解为规模逐渐减小的同类型的子问题。 

动态规划法与分治法的一个重要的不同点在于,用分治法分解后得到的子问题通常都是相互独立的, 而用动态规划法分解后得到的子问题很多都是重复的。因此,对重复出现的子问题,只是在第一次遇到时才进行计算,然后把计算所得的结果保存起来;当再次遇到该子问题时,就直接引用已保存的结果,而不再重新求解。 

简述求矩阵连乘最少乘法次数的动态规划算法(不超过300字)

答:按照做最后一次乘法的位置进行划分, 

该矩阵连乘一共可分为j-i种情况即有(j-i)种断开方式: 

Mi(Mi+1┅Mj),(MiMi+1)(Mi+2┅Mj),┅,(MiMi+1┅Mj-1)Mj。 

其中任一对括号内的矩阵个数(即规模)不超过j-i。

由于在此之前我们已知 任一个规模不超过j-i的矩阵连乘所需的最少乘法次数, 故(Mi┅Mk)和(Mk+1┅Mj)所需的最少乘法次数已知, 将它们分别记之为mik和mk+1,j。 于是,形为(Mi⋯Mk)(Mk+1⋯Mj)的矩阵连乘所需的最少乘法次数为:mik+mk+1,j+ri-1×rk×rj。 此式中的所有参加运算的数均已知, 故此式在O(1)时间里即可完成计算。 对满足i≤k<j 的共j-i种情况逐一进行比较,我们就可以得到矩阵连乘MiMi+1┅Mj-1Mj(i<j)所需的最少乘法次数mij为:

mij=min(i≤k<j){mik+mk+1,j+ri-1×rk×rj},(*) 其计算可在O(j-i) 时间里完成。

于是在初始时我们定义mii=0(相当于单个矩阵的情况), 然后首先求出计算M1M2, M2M3, ┅, Mn-1Mn 所需的乘法次数mi,i+1(i=1,2,┅,n-1), 具体数值为ri-1×ri×ri+1, 因mii= m i+1, i+1=0; 再利用这些结果和(*)式,就可以求出 计算M1M2M3, M2M3 M4, ┅, Mn-2Mn-1Mn 所需的最少乘法次数mi,i+2(i=1,2,┅,n-2)。 同理,可依次算出mi,i+3(i=1,2,┅,n-3),mi,i+4(i=1,2,┅,n-4),┅, 直至算出m1,n即M1M2┅Mn-1Mn矩阵连乘所需的最少乘法次数。

能够用动态规划法求解的问题通常具有什么样的特征?

答:若一个问题可以分解为若干个高度重复的子问题, 且问题也具有最优子结构性质,就可以用动态规划法求解: 以递推的方式逐层计算最优值并记录必要的信息, 最后根据记录的信息构造最优解。

什么是最长公共子序列问题?在求LCS的算法中,C[i,j]是如何计算的?为什么需要这样计算?

答:若Z<X,Z<Y,且不存在比Z更长的X和Y 的公共子序列, 

则称Z是X和Y 的最长公共子序列,记为Z∈LCS(X,Y)。如何在低于指数级的时间复杂度内找到LCS称为最长公共子序列问题

    C[i,j]=0, 若i=0或j=0

C[I,j]=C[i-1,j-1]+1 若i,j>0且xi=yi

C[I,j]=max{C[i-1,j],C[i,j-1]} 若i,j>0且xi!=yi

二维数组C,用C[i,j]记录Xi与Yj的LCS的长度 如果我们是自底向上进行递推计算,那么在计算C[i,j]之前, C[i-1,j-1], C[i-1,j]与C[i,j-1]均已计算出来。此时我们 根据X[i]=Y[j]还是X[i]≠Y[j],就可以计算出C[i,j]。

    计算的理由:求LCS(Xm-1,Y)的长度与LCS(X,Yn-1)的长度 这两个问题不是相互独立的: ∵两者都要求LCS(Xm-1,Yn-1)的长度, 因而具有重叠性。 另外两个序列的LCS中包含了两个序列的前缀的LCS, 故问题具有最优子结构性质 考虑用动态规划法。

用200~300字概述求最优二分搜索树算法的主要步骤。算法中有哪几点最为关键?

答:记cij是最优子树Tij的耗费, 则ci,k-1是最优子树Ti,k-1的耗费,ck,j是最优子树Tk,j的耗费。 考察以ak (i+1≤k≤j)为根、由结点bi,ai+1,bi+1,⋯,aj,bj构成的、 耗费最小的树的总耗费:该树的左子树必然是Ti,k-1,右子树必然是Tk,j。 这棵树的总耗费可分为三部分:左子树、右子树和根。 由于Ti,k-1作为左子树接到结点ak之下时,其耗费增加wi,k-1, 故左子树的耗费为:ci,k-1+ wi,k-1, 同理,右子树的耗费为:ck,j+wk,j, 由于根ak的深度为0,按定义,根的耗费为pk。 因此,以ak 为根、耗费最小的树的总耗费为:ci,k-1+ wi,k-1+ckj+wk,j+pk。 注意到,wi,k-1=qi+pi+1+qi+1+⋯+pk-1+qk-1, wk,j=qk+pk+1+qk+1+⋯+pj+qj, 从而有wi,k-1+wkj+pk = qi+pi+1+qi+1+⋯+pk-1+qk-1+ pk +qk+pk+1+qk+1+⋯+pj+qj = wij。 由此得到以ak 为根、耗费最小的树的总耗费为:ci,k-1+ckj+wi,j

由于pi(i=1,2,⋯,n), qj(j=0,1,2,⋯,n)在初始时已经知道, 若wi,j-1已知,则根据wi,j= wi,j-1+pj + qj可以计算出wij。 故当ci,k-1与ckj已知时,以ak 为根的树的最小总耗费 在O(1)时间就可以计算出来。 分别计算以ai+1,ai+2,⋯,aj为根、 含有结点bi,ai+1,bi+1,⋯,aj,bj的树的最小总耗费, 从中选出耗费最小的树,此即最优子树Tij。 因此,最优子树Tij的耗费cij={cminj k i ≤ <j k i ≤ <i,k-1+ckj+wij}。 递推求cij及记录Tij的根的算法

本算法的关键点:分析出最优二分搜索树具有最优子结构;在计算中规模较小的最优子树在计算中要被多次用到。Cij和Wij都是可以通过前面的计算递推得出的。

有了Tij的根的序号后,如何构造出最优二分搜索树?

答:设Tij的根为ak (rij记录到的值是k),则从根开始建结点。 

Build-tree(i,j,r,A) /*建立最优子树Tij*/ 

{If i≥j return "nill"; 

pointer←newnode(nodetype); 

k←rij; /*必有i < m ≤ j*/ 

pointer→value←A[k]; /*A[k]即ak*/ 

pointer→leftson←Buildtree(i,k-1,r,A); /*建立最优左子树Ti,k-1*/ 

pointer→rightson←Buildertree(k,j,r,A); /*建立最优右子树Tk,j*/ 

return pointer; 

Francis Yao的办法为什么会把算法时间复杂度从O(n3)降到O(n2)?

答:Th: 如果最小耗费树Ti,j-1和Ti+1,j的根分别为ap和aq,则必有 

⑴p≤q ⑵最小耗费树Tij的根ak满足p≤k≤q。 (证明略。)

有了上述定理,我们无需在ai+1~aj之间去一一尝试,使得找到的ak为根时,{ci,k-1+ckj+wij}为最小,而只要从ap~aq之间去找一个根即可。

算法时间复杂度为Θ(n2)的证明: 

首先注意Ti,j-1和Ti+1,j的规模恰好比Ti,j小1。由于算法是按树中结点的个数(即规模)从小到大计算的,故在计算rij时,ri,j-1(即定理中的p)和ri+1,j(即定理中的q) 

都已经计算出来了。一般地,设含有k个连续结点的最优二分搜索子树的根 

r0k,r1(k+1),⋯,r(n-k),n已经计算出来。由Th知, 含有k+1个连续结点的最优二分搜索子树Ti, i+k+1的根 必在ri,i+k与ri+1,i+k+1之间。 

故r0,k+1在r0,k与r1,k+1之间, 求出r0,k+1的搜索区间长度为r1,k+1-r0,k; 

r1,k+2在r1,k+1与r2,k+2之间,求出r1,k+2的搜索区间长度r2,k+2 -r1,k+1; 

r2,k+3在r2,k+2与r3,k+3之间,求出r2,k+3的搜索区间长度r3,k+3 -r2,k+2; 

⋯⋯ r(n-k-1),n在r(n-k-1),n-1与r(n-k),n之间, 

求出r(n-k-1),n的搜索区间长度为r(n-k),n-r(n-k-1),n-1;  

于是,求出所有规模为k+1的最优二分搜索子树的根 

r0,k+1, r1,k+2,⋯,r(n-k-1),n的搜索长度的总和= 

(rn-k,n-rn-k-1,n-1)+⋯+( r3,k+3 -r2,k+2)+(r2,k+2-r1,k+1)+(r1,k+1-r0,k)=r(n-k),n-r0,k 

∵rn-k,n最多为n,r0,k最小为1, 

∴搜索区间长度最多为Θ(n),即第2层循环执行总次数为Θ(n), 

因此算法总的时间复杂度为Θ(n2)。 

用200~300字概述二维流水作业调度算法的主要步骤

答:求解该问题的算法如下。 

1. 建立长为2n的数组C,将a1, a2,┅, an依次放入C[1]~ C[n]中,b1, b2,┅, bn依次放入C[n+1]~ C[2n]中。 /* O(n), 下面将对这2n个数进行排序*/ 

2. 对长为2n的数组D进行初始化:D[1]~ D[n]中依次放1,2,┅,n,D[n+1]~ D[2n]中依次放-1,-2,┅,-n。 /* O(n), 分别对应于a1, a2,┅, an和b1, b2,┅, bn的下标*/ 

3. 对数组C进行排序,D[k]始终保持与C[k]的对应关系。 

(若C[i]与C[j]对换,则D[i]也与D[j]对换。

或将C,D放在同一结构体中。) 当a1, a2,┅, an及b1, b2,┅, bn按从小到大次序排好之后,

D[1]~ D[2n]也就按从小到大的次序记录了这些ai和bj的下标即作业号(bj的下标前有一负号以区别于ai))。/*O(n log n)*/

 4. 将E[1]~ E[n]全部置为"No"。 /* O(n),表示所有任务均尚未被安排*/

 5. 下标变量初始化:i←1;j←n;k←1;

 /*O(1),i指向当前最左空位F[i],放当前应最先安排的作业号;*/ /* j指向当前最右空位F[j],放当前应最后安排的作业号;*/ /* k从1开始逐次增1,*/ /* D[k](或-D[k])按ai和bj从小到大的次序依次给出作业号*/

 6. while i ≤ j

 do { /* 作业尚未安排完毕,i从小到大, j从大到小*/

 if D[k] > 0 then {if E[D[k]]为"No"then /*作业D[k]放在当前最左空位*/ {F[i]←D[k]; i增1; E[D[k]] 置为"Yes"}} 

else if E[-D[k]]为"No"then /*作业-D[k]放在当前最右空位*/ {F[j]←-D[k]; j减1; E[-D[k]] 置为"Yes"}}

 k增1;}

什么是备忘录方法?它在什么情况下使用较为有效?

答:若有大量的子问题无需求解时,用备忘录方法较省时。 

但当无需计算的子问题只有少部分或全部都要计算时, 

用递推方法比备忘录方法要好(如矩阵连乘,最优二分搜索树)。

简单不相交集的合并算法中为什么要引进集合的外部名和内部名?

答::若没有内部名, 

则每次合并时两个集合中的所有元素均要改名(改为K), 

这样,在n-1次Union中改名的时间就变为O(n2) 。 

什么是平摊分析?平摊分析常用的手法有哪几种?简单说明这几种手法的要点。

答:考虑n条指令执行的最坏时间复杂性。 即使某些指令执行时具有比较大的代价, 

但利用平摊分析后对整体考虑, 可以得到较小的平均代价。

平摊分析方法主要有:聚集方法,会计方法和势能方法。

聚集方法:全局考虑时间复杂性, 把n条指令的耗费分为几类; 分别计算每一类耗费的总和, 然后再把各类耗费总加起来。

会计方法:利用几个操作之间的联系,在一个操作中预先支付下面某个操作的费用,以达到简化代价计算的目地。

势能方法:设Ci为第i个操作的实际代价, 

D0为处理对象的数据结构的初始状态, 

Di为第i个操作施加于数据结构Di-1之上后数据结构的状态, 

引入势函数Φ,Φ(Di)是与Di相关的势。 

定义第i个操作的平摊代价为: 

= Ci +(Φ(Di)- Φ(Di-1))(即实际代价加上势的变化), 

为什么树结构下执行O(n)条带路径压缩的Union-Find指令只需要O(n*G(n))时间?

答:用平摊分析的聚集方法,把O(n)条Find指令的耗费分为三类: 

1) O(n)条Find指令的根费用, 

2) O(n)条Find指令的组费用, 

3) O(n)条Find指令的路径费用。

根费用:执行一条Find指令时,处理根及其儿子所需的费用。 一条Find指令只会碰到一个根(及其儿子), 故O(n)条Find指令的根费用为O(n), 这样,根及其儿子的费用已全部计算在内。

组费用:若结点ik (0≤k≤m-2)与其父结点ik+1的秩不在同一个秩组中, 则对ik收取一个组费用。因最多有G(n)个组, 故一条Find指令最多只会碰到G(n)个结点、 其秩与其父结点的秩不在同一个秩组中, 故O(n)条Find指令的组费用最多为O(n*G(n))。

路径费用:由于其秩在组号为g的组中结点的个数不超过n/F(g), 故组g中的结点的收取的路径费用 不超过[n/F(g)]*[F(g)-(F(g-1)+1)]< [n/F(g)]*F(g)=n。 因总共只有G(n)个组, 故所有结点在O(n)条Find指令的执行中, 收取的路径费用不超过O(n*G(n))。

三项费用总加起来,有O(n)+ O(n*G(n))+O(n*G(n))=O(n*G(n)) 于是可得结论:如果合并是是把小集合并入大集合, 且执行Find指令时实施路径压缩,则执行O(n)条Unoin-Find指令的时间复杂度为O(n*G(n));

树结构下执行O(n)条带路径压缩的Union-Find指令能否降到线性即O(n)时间?

答:执行O(n)条Unoin-Find指令时,对于任意的c,都存在一个特殊的Unoin-Find指令序列, 

使得执行该序列的时间复杂度>cn, 即算法在最坏情况下不是线性的。 

用200~300字概述Link(v,r)程序的执行过程。该程序的要点在什么地方?

答:要点在于:为保持Weight的性质,合并的同时要对Weight[r']进行修改。(由于原先的Link就是把r接到v之下,而含有v的树中各结点的深度并未受到任何影响,现在把Tr接在v'之下,Tv中的各结点当然也不会受到任何影响, 故Tv树中各结点的Weight值无需修改。)Tr树中各结点的Weight值如何修改? 

  设用Find-Depth指令可以查到v的深度为Depth(v), 

(注意Depth(v)是Find-Depth指令的返回值而不是函数) 而在原先的森林中,由于r是根,故原先有Depth(r)=0(也是值)。 

执行Link指令后,把r作为v的儿子, 

则此时在原先的森林中,r的深度为Depth(v)+1。 

设在D-森林中,r'的儿子是s。 

由Weight的性质,在D-森林中的2棵树合并之前,有: 

从r到s路径上各结点的权和+旧Weight[r']=0(r在原森林中的深度) 

D-森林中的2棵树合并之后,在原先森林中r的深度为 

从r到s的权和+新Weight[r']+Weight[v'](按Weight的性质), 

另一方面,按上述分析,在原先森林中r的深度为Depth(v)+1, 

故有从r到s的权和+新Weight[r']+Weight[v']= Depth(v)+1。 

由上述两式可得: 

新Weight[r']=Depth[v]+1-Weight[v']+旧Weight[r']。 

由于Tr中的其它各结点相对于r'的位置合并后均未改变, 

故Tr中的其它各结点的Weight值无需改变, 

只要r'的新Weight值正确, 

则Tr中的其它各结点就都能够正确计算出其在原森林中的高度。 

2、Count[v']< Count[r']时,把v'作为r'的儿子。 

合并后应有:从r到s的权和+新的Weight[r']= Depth(v)+1。 故有新的Weight[r']= Depth(v)+1+旧Weight[r']。 另外,Weight[v']也要修改。 设在D-森林中,v'的儿子是t,则合并前有: 从v到t的权和+旧Weight[v']=Depth(v) (v在原森林里的深度)。 而合并以后应有: 从v到t的权和+新Weight[v']+新Weight[r']=Depth(v) (合并时是将r接到v之下,故v在原森林里的深度并不改变。) 2式联立得 新Weight[v']=旧Weight[v']-新Weight[r']。 不论哪一种情况,权修改完后 都要将新根的Count值改为Count[v']+Count[r']。 Link程序中,除了Find-Depth(v)(以找到根v'并计算出Depth(v))、 Find(r)(以找到根r')外,其余部分的执行时间是常数, 而Find-Depth的时间复杂度与Find的同阶, 故O(n)条Link和Find-Depth可以在O(n*G(n))里完成。

你认为脱线MIN算法的关键点在什么地方?

答:算法: 

for i=1 to n do { 

j←FIND(i); 

if j=0 then {输出"i未在序列中出现"} 

else if j>k then {输出"i未被删除"} 

else{ /* i确实被删除了*/ 

输出"i被第j条E指令所删除"; 

UNION(j,Succ[j],Succ[j]); 

Succ[Pred[j]]←Succ[j];/* 集合j不再存在*/ 

Pred[Succ[j]]←Pred[j] 

} } 

算法最关键的在于集合的Union和find算法的使用。

比较Las Vegas算法和Monte Carlo算法,它们有什么相同和相异之处?随机算法有哪些优点?答:LasVegas算法总是给出正确的结果, 

但在少数应用中,可能出现求不出解的情况。此时需再次调用算法进行计算,直到获得解为止。对于此类算法,主要是分析算法的时间复杂度的期望值,以及调用一次产生失败(求不出解)的概率。Mont Carlo算法通常不能保证计算出来的结果总是正确的,一般只能断定所给解的正确性不小于p(<p<1=。通过算法的反复执行(即以增大算法的执行时间为代价),能够使发生错误的概率小到可以忽略的程度。由于每次执行的算法是独立的,故k次执行均发生错误的概率为(1-p)k。

随机算法的优点: 

1. 对于某一给定的问题,随机算法所需的时间与空间复杂性, 往往比当前已知的、最好的确定性算法要好。 

2. 到目前为止设计出来的各种随机算法,无论是从理解上还是实现上,都是极为简单的。 

3. 随机算法避免了去构造最坏情况的例子。 最坏情况虽有可能发生,但是它不依赖于某种固定的模式,只是由于"运气不好"才出现此种情况。 

简述随机取数算法和找第k小元素的随机算法。

答:Random Sampling问题(Las Vegas算法) 

设给定n个元素(为简单起见,设为1,2,⋯n),要求从n个数中随机地选取m个数(m≤n)。可以用一个长为n的布尔数组B来标识i是否被选中,初始时均表为"未选中"。然后随机产生〔1,n〕之间的一个整数i,若B[i]为"未选中",则将i加入被选中队列, 同时把B[i]标识为"已选中",反复执行直到m个不同的数全部被选出为止。 

找第k小元素的随机算法(Las Vegas算法):

在n个数中随机的找一个数A[i]=x, 然后将其余n-1个数与x比较,分别放入三个数组中: S1(元素均<x), S2(元素均=x), S3(元素均>x)。 若|S1|≥k 则调用Select(k,S1); 若(|S1|+|S2|)≥k,则第k小元素就是x; 否则就有(|S1|+|S2|)< k,此时调用Select(k-|S1|-|S2|,S3)。

什么是Sherwood随机化方法?简述Testing String Equality算法的误判率分析。

答:Sherwood随机化方法(属Las Vegas算法) 如果某个问题已经有了一个平均性质较好的确定性算法, 但是该算法在最坏情况下效率不高,此时引入一个随机数发生器 (通常是服从均匀分布,根据问题需要也可以产生其他的分布),将一个确定性算法改成一个随机算法,使得对于任何输入实例, 该算法在概率意义下都有很好的性能(e.g. Select, Quicksort等)。 如果算法(所给的确定性算法)无法直接使用Sherwood方法, 则可以采用随机预处理的方法,使得输入对象服从均匀分布 (或其他分布),然后再用确定性算法对其进行处理。 所得效果在概率意义下与Sherwood型算法相同。

数论定理1:设π(n)是小于n的素数个数,则π(n)≈nnelog, 误差率不超过6%。

∵M=2n2,Pr[failure]的分母 π(M)≈

Pr[failure]的分子 ≤ 使得Ip(x)=Ip(y)的素数p(p<M)的个数 =能够整除︱I(x)-I(y)︱的素数p(p<M)的个数 (∵a≡b (mod p) iff p整除︱a-b︱)

数论定理2:如果a<2n,则能够整除a的素数个数不超过π(n)个。 (只要n不是太小。)

∴Pr[failure]≤π(n) / π(M)≈nnnneelog/log/2=n1。即误匹配的概率小于n1。

设x≠y,如果取k个不同的小于2n2的素数来求Ip(x)和Ip(y), 由于事件的独立性,因此事件均发生的概率满足乘法规则, 即k次试验均有Ip(x)=Ip(y)但x≠y(误匹配)的概率小于kn1。 ∴当n较大、且重复了k次试验时,误匹配的概率趋于0。

计算模型RAM与RASP之间有什么相同和相异之处?

答:RAM和RASP的相同之处在于作为计算模型都有各种寻址指令,且任何一个RAM程序,都可由一个RASP程序来模拟实现, 且时间复杂性数量级相同(不论哪一种耗费标准)。 

即如果RAM程序的时间复杂度为T(n),则RASP实现同样功能的程序的时间复杂度为kT(n)(k为常数)。任何一个RASP程序都可由RAM程序来模拟, 且时间复杂性的量级相同(无论哪一种耗费标准)。RASP程序与RAM程序之间可以相互模拟, 且无论哪一种耗费标准,两者的时间复杂性的量级均相同。

   不同之处在于:RAM的程序一经给定就不允许修改;而RASP(Random Access Stored Program)的程序可以修改,只要将程序放在存储器上就可以。RASP程序没有间接寻址

Alan Turing是怎样对人类计算过程进行概括的?

答:Turing 根据这个过程构造出了一个计算模型,称之为Turing机。

这个计算模型有一条带子(带子相当于一张纸),带子上有无穷多个方格,每个方格中可以写给定有穷符号表中的一个字符。有一个读写头(读相当于用眼睛来看,写相当于擦或写)。 还有一个有穷状态控制器FSC(相当于人脑),FSC根据当前读到的符号(相当于眼睛看到的)和 

自己当前的状态(相当于人脑的决策)决定三件事:  

改变读写头当前所指的字母(相当于在纸上改写一些符号),改变(或不改变)自己当前的状态(准备下一步的计算),使读写头左移或右移或不动(相当于改变眼睛看到的范围)。 

Church-Turing Thesis的内容是什么?它有什么意义?

答:任何合理的计算模型都是相互等价的(计算范围相同)。 

合理:单位时间内可以完成的工作量,有一个多项式的上限。不合理举例:任意多道的并行计算。由于有"任何"二字,故无法进行证明。但迄今为止所有被提出的合理计算模型均满足该论题。

这个论题说明:可计算性本身是不依赖于具体模型的客观存在。

RAM程序、RASP程序与Turing机相互之间的时间复杂度关系是怎样的(考虑两种耗费标准)?

答:任何一个RAM程序,都可由一个RASP程序来模拟实现,且时间复杂性数量级相同(不论哪一种耗费标准)。即如果RAM程序的时间复杂度为T(n),则RASP实现同样功能的程序的时间复杂度为kT(n)(k为常数)。

   当一台TM的时间复杂度为T(n)时,模拟该TM的RAM程序的对数耗费不超过O(T(n)logT(n)); 而当一不含乘、除法指令的RAM程序的对数耗费为T(n)时,模拟该程序的TM的时间复杂度不超过O(T2(n));当一含有乘、除法指令的RAM程序的对数耗费为T(n)时, 

模拟该程序的TM的时间复杂度不超过O(T3(n))。

   在对数耗费的标准下, RAM,RASP与TM是多项式相关的计算模型。

RASP程序如何模拟RAM程序?RAM如何模拟Turing机? Turing机如何模拟RAM?

答:RASP程序按下图模拟RAM程序:

   

在模拟过程中,RASP的第r+i号寄存器 始终对应于RAM的第i号寄存器,RASP的R1作为暂存器。 R0与r0在一条指令的模拟过程中可能不对应,但在一条指令模拟的开始和结束时一定对应。 

模拟非间址寻址指令时,先将指令对应的编码放入j寄存器,若操作数为"=i",则去掉"=",将i放入j+1寄存器,若操作数为"i",要看i是否为0:i为0时,将0放入j+1寄存器,i>0时,将r+i放入j+1寄存器。间址寻址的RAM指令,可以用一组RASP指令来模拟实现。 

RAM模拟TM的方法如下图:

 

模拟时存储内容的对应方法按上图所示。TM的k个带头的位置分别放在RAM的单元r1至rk中,即第j个单元的内容C(j)就是第j个带头在第j条带上的当前位置。c为RAM存储器中存放a0的单元之前的单元编号。k条带上的首格内容(分别为a0,b0,⋯,z0)存放在 第c号单元后的k个单元中;其后再放k条带上的次格内容(分别为a1,b1,⋯,z1);因此,TM的第j条带当前扫描着的单元的内容是存放在RAM存储器的第c+k*C(j)+j个单元中,即内容为C(c+k*C(j)+j)。 

(C(j)是第j个带头的当前位置,而位置的计数是从0开始的)。e.g.:第二条带第1个格子中的内容放在第c+k*1+2号单元。 

TM模拟RAM的方法如下图:

  

用5带TM来模拟RAM程序的过程:  

带1用来记录内容为非0的RAM寄存器的编号及该寄存器的内容。带2存放RAM累加器r0中的内容α0,带3作为暂存工作带。带4上放RAM输入带上的内容,带5上放输出。 

Turing机所接受的语言是什么样的语言? 各种语言之间有什么样的关系?

答:Turing可计算函数部分递归函数。

递归可枚举集>(完全)递归集>原始递归集

部分递归函数>完全递归函数>原始递归函数

非确定性Turing机与确定性Turing机的主要区别在什么地方?

答:与DTM不同的是,NDTM的每一步动作允许有若干个选择,对于给定的Q×Tk的一个元素(qi, a1, a2,⋯, ak),它的δ转移函数值不是对应于一个Q×(T×{L,R,S})k中的一个元素,而是对应于Q×(T×{L,R,S})k中的一个子集。  

与DTM不同的是,DTM的 ID序列是线性的: ID0├ ID1├ ID2├ ┅├ IDm, 而NDTM的ID序列通常是用树来描述的 (因为在每个格局都可能有多个选择)。

NDTM的另一种解释是,每当遇到n个(n≥2)选择时, NDTM就把自身复制n个,让它们进行并行的计算。 由于具有任意多道并行计算的能力,

非确定性Turing机的时间复杂度是如何定义的?

答:NDTM的时间复杂度T(n): 对于可接受的输入串, T(n)=max{关于输入ω的时间复杂度 | ω的长为n且被该NDTM接受} 即先求出每一个被接受ω的最短路径长度,然后对这些长度求最大。

 

什么是P类与NP类语言?如不用非确定性Turing机的概念,如何定义P类与NP类的问题?答:语言族P=﹛L|L是一个能在多项式时间内被一台DTM接受的语言﹜ 

NP=﹛L|L是一个能在多项式时间内被一台NDTM接受的语言﹜

不需要NDTM概念的NP问题的定义 

设S是一个集合,若某个判定问题A的所有解均属于S, 则S中的一个元素称为问题A的一个证书(certificate),S被称为是A的证书所构成的集合。对判定问题类A,若存在一个由A的证书所构成的集合S (S中含有A的全部解),且存在一个算法F,对S中的每一个证书α, F可在多项式时间里验证α是否为A的一个解,则称A∈NP。 (该定义与用NDTM概念的NP类定义是等价的。)

称P类问题是多项式时间可解的。 称NP类问题是多项式时间可验证的。

Karp多项式规约是如何表述的?它与Cook多项式规约之间的关系如何?

答:Karp规约:设L、L0分别是字母表∑、∑0上的语言(字符串的集合), 

若存在两个闭包间的一个变换f:∑*→∑∗,满足 

1) ∀ω∈∑*,ω∈L⇔f(ω)∈L0; 

2) 若ω 的长为n,则f(ω)的长不超过PL(n),这里PL(n)是一个多项式; 

3) 任取ω∈∑*,设ω的长度为n,则f (ω)在多项式时间p(n)内可计算。 

则称L可多项式变换为L0,记作L≤p L0。

它和Cook规约的关系是Karp的要求严,Cook的要求松,即满足Karp就满足Cook。

至今尚未发现满足Cook而不满足Karp的语言,即两者大体等价。Karp的定义简洁,Cook的定义繁琐。

什么是NP-完全性语言?什么是NP-完全性问题?什么是NP-hard问题?

答:NP-完全性语言 

定义1(狭义,Karp):称满足下述2条的语言L0是NP-C的: 

1)L0∈NP; 2) ∀L∈NP,都有L≤pL0。 

NP-完全性问题 :若某个判定问题进行编码后,所对应的语言L0是NP-C的, 则称该问题是NP-C的。

 

有些最优化问题(对应的编码ω∈L0)可以满足 NP-完全性定义的第2条要求:∀L∈NP,都有L≤p L0。 满足上述条件的问题被称为NP-hard问题。

 

引入NP-完全性概念有什么意义?列举20个NP-完全性或NP-hard问题。

答:如果存在一台DTM在多项式时间里接受某个NP-C语言, 

则所有NP类语言均可找到DTM在多项式时间里接受,从而有P=NP。 

如果某个NP类语言不存在DTM在多项式时间里接受(即P≠NP), 

则所有NP-C语言都不存在DTM在多项式时间里接受, 

即有NP-C∩P=Φ。 

什么是算法A对于实例I的近似比、A的绝对近似比和渐进近似比?

答:算法A对于实例I的近似比(ratio factor) =RA(I)=max{A(I)/OPT(I),OPT(I)/A(I)} 

由于是取max,故近似比总是大于等于1的。 

绝对近似比rA=Inf{RA(I)} 对一切 即算法A对于一切实例I的近似比的最小上界(相当于最大值)。 

渐进近似比rA=sup{r≥1| 存在正整数n0, 使得对于所有OPT(I)≥n0的实例,都有≤r} 即反映了近似比的收敛情况,它允许OPT(I)较小的实例的近似比大于rA。 

什么是多项式时间近似方案(PTAS)?什么是完全多项式时间近似方案(FPTAS,FPAS)?

答:多项式时间近似方案 (PTAS, Polynomial Time Approximation Scheme) 

设ε是求解某类问题的多项式时间近似算法, 

ε>0也作为该算法的输入。如果对每一个给定的ε, 

的绝对近似比≤1+ε,则称A 是一个PTAS。 

完全多项式时间近似方案 (FPTAS,FPAS, Fully Polynomial Time Approximation Scheme) 

如果一个PTAS 以某个二元多项式函数p(|I|,1/ε) 

为时间复杂度上界,则称ε是一个FPTAS。

什么是伪多项式时间的算法?如何用动态规划法求解背包问题?

答:定义:设实例I的输入规模为n,实例中的最大数为max(I), 若算法的时间复杂性以某个二元多项式p(n,max(I))为上界, 则称该算法是伪多项式时间的算法。

动态规划法。对0≤k≤n,0≤b≤B,设f(b)为: 

装前k件物品中若干件、且体积和不超过b时可得到的最大价值。 

因此,f(B)就是该问题的最优解。 

根据f(b)的定义可知子问题具有最优子结构性质。 

 

另外,引入初值均为0的二维数组x,每一个数组元素x[k,b]记录: 

当体积限制为b时,uk是否被选中,1为被选中,0为未被选中。 

初始当k=0时,有(b)=0(0≤b≤B),此为递推计算的基础值。 

设对b∈[0,B],(b),(b),⋯,f(b)均已计算出来, 

此时需要对区间[0,B]中的整数b(即0≤b≤B),逐一求出(b)。 

考虑b与sk的关系。 

若b < sk,则对于体积限制b,物品uk根本不能装(太大了), 

∴x[k,b]应为0(即此时不选物品uk);同时执行fk(b)←fk-1(b)。 

(实际执行时,只要对小于sk的b,执行fk (b)←fk-1 (b)。) 

若b≥sk,就要看把一些物品取出,再把物品uk放入, 

所得的总价值是否比不装物品uk(其总价值为fk-1 (b))时大。 

而装物品uk时,可获得的最大价值为fk-1 (b-sk)+ck。 

这里的fk-1 (b-sk)是:当体积限制不超过b-sk时, 

装前k-1件物品中的若干件,可得到的最大价值。 

若fk-1 (b-sk)+ck >(b),则物品uk应装入, 

即此时要执行x[k,b]←1,以及fk (b)←fk-1 (b-sk)+ck。 

否则应执行x[k,b]←0,以及fk (b)←fk-1 (b)。 

按上述方法,当执行到k=n,b=B时,最优解的值即为(B)。 

这部分算法的时间复杂度为O(nB)。 

上述计算完毕之后,再根据x数组内容,找出应取哪几件物品。 

置初值b=B,循环从j=n开始,检查x[j,b]: 

若x[j,b]=0,则表示uj未被选中,故不做动作,直接执行j←j-1; 

若x[j,b]=1,则表示uj被选中,把j放入集合S中(S初始为空), 

然后执行b←b-sj以及j←j-1。 

循环一直执行到j=1的判断完成后为止。算法时间复杂度为O(n)。 

从而整个算法的时间复杂度为O(nB)。 

注意B与输入规模n无关,故nB不是输入规模的多项式函数。 

因此,算法是伪多项式时间的算法。 

NP-hard问题在PNP的假定之下,可以分成哪4类(举例)?

答:NP-hard问题在P≠NP的假定之下,可以分成4类:

 1、 有FPTAS(e.g.Knapsack)

 2、 有PTAS而没有FPTAS(e.g. k-Knapsack)

 3、 没有PTAS,但有绝对近似比为常数的近似算法(Bin-Packing) 

4、 没有绝对近似比为常数的近似算法(e.g. TSP)

为什么当k≥2,k背包问题不存在FPTAS,除非P=NP?

答:反证法:设A是该问题的FPTAS,时间复杂度上界为P(|I|,1/ε), 

对每个实例I,令ε=1/2ncmax,将I和ε作为A的输入, 

由于A是FPTAS,故有OPT(I)≤(1+ε)A(I), 

∴0≤OPT(I)-A(I)≤εA(I)≤ε≤εncmax=。 

但OPT(I)和A(I)都是正整数,∴OPT(I)=A(I), 

故A(I)是最优化算法,其时间复杂度上界为p(n,2ncmax)。 

利用算法A来构造k等分割问题的算法A': 

对于k等分割的任一实例I,即n个正整数sj (1≤j≤n), 

构造k背包问题的实例I':物品j的体积为sj, 

价值cj=1(1≤j≤n),背包容量Bi=(1≤i≤k)。 

将该实例I'和ε==作为A的输入,求得I'的最优解A(I'); 

当且仅当OPT(I')=n(把所有物品均装入k个背包)时, 

A'对I回答为"Yes"。 

注意,k等分割有解 iff A'回答为"Yes" 

由于根据I构造I'仅需O(n)时间,|I'|=|I|=n,ε=, 

而A算法的时间复杂度上界不超过p(n,)=p(n,2n), 

是关于n的多项式,∴A'是k等分割问题的多项式时间算法, 

即找到了一个求解NP-C问题的多项式时间算法, 

∴P=NP,与P≠NP矛盾。 

结论:假设P≠NP,则k背包问题没有FPTAS。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值