算法设计与分析王晓东
- 格式:doc
- 大小:53.00 KB
- 文档页数:14
习题2-1 求下列函数的渐进表达式:3n^2+10n; n^2/10+2n; 21+1/n; logn^3; 10 log3^n 。
解答:3n^2+10n=O(n^2),n^2/10+2^n=O(2^n),21+1/n=O(1),logn^3=O(logn),10log3^n=O(n).习题2-3 照渐进阶从低到高的顺序排列以下表达式:n!,4n^2,logn,3^n,20n,2,n^2/3。
解答:照渐进阶从高到低的顺序为:n!、3^n、4n^2 、20n、n^2/3、logn、2习题2-4(1)假设某算法在输入规模为n时的计算时间为T(n)=3*2^n。
在某台计算机上实现并完成该算法的时间为t秒。
现有另外一台计算机,其运行速度为第一台计算机的64倍,那么在这台新机器上用同一算法在t秒内能解输入规模为多大的问题?(2)若上述算法的计算时间改进为T(n)=n^2,其余条件不变,则在新机器上用t秒时间能解输入规模多大的问题?(3)若上述算法的计算时间进一步改进为,其余条件不变,那么在新机器上用t秒时间能解输入规模多大的问题?解答:(1)设能解输入规模为n1的问题,则t=3*2^n=3*2^n/64,解得n1=n+6(2)n1^2=64n^2得到n1=8n(3)由于T(n)=常数,因此算法可解任意规模的问题。
习题2-5 XYZ公司宣称他们最新研制的微处理器运行速度为其竞争对手ABC公司同类产品的100倍。
对于计算复杂性分别为n,n^2,n^3和n!的各算法,若用ABC公司的计算机能在1小时内能解输入规模为n的问题,那么用XYZ公司的计算机在1小时内分别能解输入规模为多大的问题?解答:n'=100nn'^2=100n^2得到n'=10nn'^3=100n^3得到n'=4.64nn'!=100n!得到n'<n+log100=n+6.64习题2-6对于下列各组函数f(n)和g(n),确定f(n)=O(g(n))或f(n)=Ω(g(n))或f(n)=θ(g(n)),并简述理由。
第一章作业1.证明下列Ο、Ω和Θ的性质1)f=Ο(g)当且仅当g=Ω(f)证明:充分性。
若f=Ο(g),则必然存在常数c1>0和n0,使得∀n≥n0,有f≤c1*g(n)。
由于c1≠0,故g(n) ≥ 1/ c1 *f(n),故g=Ω(f)。
必要性。
同理,若g=Ω(f),则必然存在c2>0和n0,使得∀n≥n0,有g(n) ≥ c2 *f(n).由于c2≠0,故f(n) ≤ 1/ c2*f(n),故f=Ο(g)。
2)若f=Θ(g)则g=Θ(f)证明:若f=Θ(g),则必然存在常数c1>0,c2>0和n0,使得∀n≥n0,有c1*g(n) ≤f(n) ≤ c2*g(n)。
由于c1≠0,c2≠0,f(n) ≥c1*g(n)可得g(n) ≤ 1/c1*f(n),同时,f(n) ≤c2*g(n),有g(n) ≥ 1/c2*f(n),即1/c2*f(n) ≤g(n) ≤ 1/c1*f(n),故g=Θ(f)。
3)Ο(f+g)= Ο(max(f,g)),对于Ω和Θ同样成立。
证明:设F(n)= Ο(f+g),则存在c1>0,和n1,使得∀n≥n1,有F(n) ≤ c1 (f(n)+g(n))= c1 f(n) + c1g(n)≤ c1*max{f,g}+ c1*max{f,g}=2 c1*max{f,g}所以,F(n)=Ο(max(f,g)),即Ο(f+g)= Ο(max(f,g))对于Ω和Θ同理证明可以成立。
4)log(n!)= Θ(nlogn)证明:∙由于log(n!)=∑=n i i 1log ≤∑=ni n 1log =nlogn ,所以可得log(n!)= Ο(nlogn)。
∙由于对所有的偶数n 有,log(n!)= ∑=n i i 1log ≥∑=n n i i 2/log ≥∑=nn i n 2/2/log ≥(n/2)log(n/2)=(nlogn)/2-n/2。
当n ≥4,(nlogn)/2-n/2≥(nlogn)/4,故可得∀n ≥4,log(n!) ≥(nlogn)/4,即log(n!)= Ω(nlogn)。
计算机算法设计与分析第1章王晓东(第三版)第4章第4章贪心算法学习要点理解贪心算法的概念。
掌握贪心算法的基本要素(1)最优子结构性质(2)贪心选择性质理解贪心算法与动态规划算法的差异理解贪心算法的一般理论通过应用范例学习贪心设计策略。
(1)活动安排问题;(2)最优装载问题;(3)哈夫曼编码;(4)单源最短路径;(5)最小生成树;(6)多机调度问题。
顾名思义,贪心算法总是作出在当前看来最好的选择。
也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。
当然,希望贪心算法得到的最终结果也是整体最优的。
虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。
如单源最短路经问题,最小生成树问题等。
在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。
4.1活动安排问题活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合,是可以用贪心算法有效求解的很好例子。
该问题要求高效地安排一系列争用某一公共资源的活动。
贪心算法提供了一个简单、漂亮的方法使得尽可能多的活动能兼容地使用公共资源。
4.1活动安排问题设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。
每个活动i都有一个要求使用该资源的起始时间i和一个结束时间fi,且i<fi如果选择了活动i,则它在半开时间区间[i,fi)内占用资源。
若区间[i,fi)与区间[j,fj)不相交,则称活动i与活动j是相容的。
也就是说,当i≥fj或j≥fi时,活动i与活动j相容。
4.1活动安排问题下面给出解活动安排问题的贪心算法GreedySelector:template<claType>voidGreedySelector(intn,Type[],Typef[],boolA[]){A[1]=true;intj=1;for(inti=2;i<=n;i++){if([i]>=f[j]){A[i]=true;j=i;}eleA[i]=fale;}}各活动的起始时间和结束时间存储于数组和f中且按结束时间的非减序排列4.1活动安排问题由于输入的活动以其完成时间的非减序排列,所以算法greedySelector每次总是选择具有最早完成时间的相容活动加入集合A中。
计算机算法设计与分析王晓东编著2-2⼆分查找算法分析使⽤⼆分查找法的前提:数组元素有序排列。
查找思想类似于分治思想。
每次都通过跟区间的中间元素对⽐,将待查找的区间缩⼩为之前的⼀半,直到找到要查找的元素,或者区间被缩⼩为 0或 -1 返回-1。
注意到⼆分查找针对的必须是已经排序过的有序数组,否则不能使⽤该算法。
设查找的元素为x。
⼆分查找的基本思想:将n个元素分为⼤致相同的两个部分[left,mid-1]和[mid+1,right]如果x==a[mid] 返回中间值索引如果x < a[mid] right = mid -1 ; 在数组的左半部分继续查找如果x > a[mid] left = mid + 1; 在数组的右半部分继续查找直到数组长度不再⼤于0 或找到元素x返回索引值。
如在数组中查找元素’10’⼜如在数组中查找’19’代码实现(C++)递归template <typename T>int BinarySearch(T a[], const T& x, int l, int r) {if (l <= r) {int mid = l + (r - l) / 2;if (a[mid] == x) {return mid;}else {if (a[mid] < x) {return BinarySearch(a, x, mid + 1, r);}else {return BinarySearch(a, x, l, mid - 1);}}}else {return -1;}}代码实现(C++)⾮递归template <typename T>int BinarySearch(T a[], const T& x, int n) { int l = 0, r = n - 1;while (l <= r) {int mid = l + (r - l) / 2;if (a[mid] == x)return mid;if (a[mid] > x)r = mid - 1;elsel = mid + 1;}return -1;}。
《计算机算法设计与分析》第二版王晓东“最大m字段和优化函数”——P57注释之所以想到要注释一下,没别的意思,只是因为几个月前刚学DP,完全看不懂,前几天费了几个小时终于看懂了,注释下来,能使自己整理一下思路,也作为自己的一篇日记。
当时我能看懂时间和空间均为O(MN^2)的函数,但可能由于自己看书是直接从动态规划一章看起,书上对于经过优化的函数也没有更多的解析,当时看起来完全不知所云。
前几天看的时候,是对着方程结合书上的几句话自己去理解,尝试自己动手去写,但错了。
看书上代码,都要自己去理解那些变量数组是干什么用的,感觉也是非常吃力。
1,我觉得理解那个优化函数,必须先要充分理解那个二维的DP方程:b[i][j]=max(b[i][j-1]+a[j],max(b[i-1][t])+a[j]) (i-1<=t<j)b[i][j]表示的是第i段在前j项(含第j项)的最大值。
对于b[i][j]含有第j项必须要理解好!则方程的意思是:对于a[j]项,要么将它加到第i段,要么它自己作为新的一段。
注意到方程外层的max选择,都要加上a[j]这一项。
这里可能很容易产生一个疑问,如果a[j]是一个负数,为什么还要加上a[j]呢?回到b[i][j]所表示的意义上解释,由于b[i][j]表示的是含有第j项的最大值,所以a[j]是肯定要加进来的。
假使a[j]是一个负数,它加进来了也不会影响在第i段中前j-1项的最大值。
所以第m段的最大值,并不是b[m][n],而是b[m][m~n]之间的最大值。
同样道理,第i-1段的最大值是b[i-1][t],(i-i<=t<j)。
2,理解了上述的DP方程后,再来考虑优化,正如书上所说的,由于在第i段中,只用到第i段和第i-1段的值。
如果采用一维数组存储b[],只要在计算第i段的时候,没有去改变第i-1段保留下来的值即可。
再考虑到,内层max选择,需要用到第i-1段在i-1到j-1位置的最大值,不但要进行重复计算,也影响到b[j]的计算,因为j前面的值既要用作b[j]的计算,也要更新作为下一段i+1计算时所用。
习题2-1 求下列函数的渐进表达式:3n^2+10n; n^2/10+2n; 21+1/n; logn^3; 10 log3^n 。
解答:3n^2+10n=O(n^2),n^2/10+2^n=O(2^n),21+1/n=O(1),logn^3=O(logn),10log3^n=O(n).习题2-3 照渐进阶从低到高的顺序排列以下表达式:n!,4n^2,logn,3^n,20n,2,n^2/3。
解答:照渐进阶从高到低的顺序为:n!、3^n、4n^2 、20n、n^2/3、logn、2习题2-4(1)假设某算法在输入规模为n时的计算时间为T(n)=3*2^n。
在某台计算机上实现并完成该算法的时间为t秒。
现有另外一台计算机,其运行速度为第一台计算机的64倍,那么在这台新机器上用同一算法在t秒内能解输入规模为多大的问题?(2)若上述算法的计算时间改进为T(n)=n^2,其余条件不变,则在新机器上用t秒时间能解输入规模多大的问题?(3)若上述算法的计算时间进一步改进为,其余条件不变,那么在新机器上用t秒时间能解输入规模多大的问题?解答:(1)设能解输入规模为n1的问题,则t=3*2^n=3*2^n/64,解得n1=n+6(2)n1^2=64n^2得到n1=8n(3)由于T(n)=常数,因此算法可解任意规模的问题。
习题2-5 XYZ公司宣称他们最新研制的微处理器运行速度为其竞争对手ABC公司同类产品的100倍。
对于计算复杂性分别为n,n^2,n^3和n!的各算法,若用ABC公司的计算机能在1小时内能解输入规模为n的问题,那么用XYZ公司的计算机在1小时内分别能解输入规模为多大的问题?解答:n'=100nn'^2=100n^2得到n'=10nn'^3=100n^3得到n'=4.64nn'!=100n!得到n'<n+log100=n+6.64习题2-6对于下列各组函数f(n)和g(n),确定f(n)=O(g(n))或f(n)=Ω(g(n))或f(n)=θ(g(n)),并简述理由。
解答:(1)f(n)=logn^2;g(n)=logn+5. logn^2=θ(logn+5)(2)f(n)=logn^2;g(n)=根号n. logn^2=O(根号n)(3)f(n)=n;g(n)=(logn)^2. n=Ω((logn)^2)(4)f(n)=nlogn+n;g(n)=logn. nlogn+n=Ω(logn)(5)f(n)=10;g(n)=log10. 10=θ(log10)(6)f(n)=(logn)^2;g(n)=logn. (logn)^2=Ω(logn)(7)f(n)=2^n;g(n)=100n^2. 2^n=Ω(100n^2)(8)f(n)=2^n;g(n)=3^n. 2^n=O(3^n)习题2-7 证明:如果一个算法在平均情况下的计算时间复杂性为θ(f(n)),则该算法在最坏情况下所需的计算时间为Ω(f(n))。
证明:Tavg(N)=IeDn∑P(I)T(N,I)≤IeDn∑P(I)IeDnmaxT(N,I')=T(N,I*)IeDn∑P(I)=T(N,I*)=Tmax(N)因此,Tmax(N)=Ω(Tavg(N))=Ω(θ(f(n)))=Ω(f(n))习题2-8 求解下列递归方程:So=0;Sn=2Sn-1+2^n-1.解答: 1应用零化子化为齐次方程,2解此齐次方程的特征方程,3由特征根构造一般解,4再由初始条件确定待定系数,得到解为:Sn=(n-1)2^n+1习题2-9 求解下列递归方程Ho=2;H1=8;Hn=4Hn-1-4Hn-2.解:Hn=2^(n+1)(n+1)第三章递归与分治策略习题3-1 下面的7个算法都是解决二分搜索问题的算法。
请判断这7个算法的正确性。
如果算法不正确,请说明产生错误的原因。
如果算法正确,请给出算法的正确性证明。
public static int binarySearch1(int []a,int x,int n){int left=0; int right =n-1;while (left<=right) {int middle = ( left + right )/2;if ( x == a[middle]) return middle;if ( x> a[middle]) left = middle;else right = middle;return -1;}public static int binarySearch2(int []a, int x, int n){int left = 0; int right = n-1;while ( left < right-1 ) {int middle = ( left + right )/2;if ( x < a[middle]) right = middle;else left = middle;}if (x == a[left]) return left;else return -1}public static int binarySearch3(int []a, int x, int n) {int left = 0; int right = n-1;while ( left +1 != right) {int middle = ( left + right)/2;if ( x>= a[middle]) left = middle;else right = middle;}if ( x == a[left]) return left ;else return -1;}public static int binarySearch4(int []a, int x, int n) {if (n>0 && x>= a[0]) {int left = 0; int right = n-1;while (left < right ) {int middle = (left + right )/2;if ( x < a[middle]) right = middle -1 ;else left = middle;}if ( x == a[left]) return left;}return -1;}public static int binarySearch5(int []a, int x, int n) {if ( n>0 && x >= a[0] ) {int left = 0; int right = n-1;while (left < right ) {int middle = ( left + right +1)/2;if ( x < a[middle]) right = middle -1;else left = middle ;}if ( x == a[left]) return left;}return -1;}public static int binarySearch6(int []a, int x, int n) {if ( n>0 && x>= a[0]) {int left = 0; int right = n-1;while ( left < right) {int middle = (left + right +1)/2;if (x < a[middle]) right = middle – 1;else left = middle + 1;}if ( x == a[left]) return left ;}return -1;}public static int binarySearch7(int []a, int x, int n){if ( n>0 && x>=a[0]) {int left = 0; int right = n-1;while ( left < right) {int middle = ( left + right + 1)/2;if ( x < a[middle]) right = middle;else left = middle;}if ( x == a[left]) return left;}return -1;}分析与解答:算法binarySearch1数组段左右游标left和right的调整不正确,导致陷入死循环。
算法binarySearch2数组段左右游标left和right的调整不正确,导致当x=a[n-1]时返回错误。
算法binarySearch3数组段左右游标left和right的调整不正确,导致当x=a[n-1]时返回错误。
算法binarySearch4数组段左右游标left和right的调整不正确,导致陷入死循环。
算法binarySearch5正确,且当数组中有重复元素时,返回满足条件的最右元素。
算法binarySearch6数组段左右游标left和right的调整不正确,导致当x=a[n-1]时返回错误。
算法binarySearch7数组段左右游标left和right的调整不正确,导致当x=a[n-1]时陷入死循环。
习题3-2 设a[0:n-1] 是已排好序的数组。
请改写二分搜索算法,使得当搜索元素x不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。
当搜索元素在数组中时,i和j相同,均为x在数组中的位置。
分析与解答:改写二分搜索算法如下:public static boolean binarySearch(int []a, int x, int left, int right, int []ind){int middle;while ( left <= right ) {middle = (left + right)/2;if (x == a[middle]) { ind[0]=ind[1]=middle; return true;}if (x > a[middle]) left = middle + 1;else right = middle -1;}ind[0] = right; ind[1]=left;return false;}返回的ind[1]是小于x的最大元素位置,ind[0]是大于x的最小元素的位置。
习题3-3 设a[0:n-1] 是有n个元素的数组,是非负整数。
试设计一个算法讲子数组与换位。