1、算法与分析平时作业答案平时作业1、给定下述二分搜索算法,请判断算法的正确性,指出错误算法的产生原因。a)int BinarySearch(Type a, const Type& x, int l, int r) while (r = l)int m = (l+r)/2;if (x = am) return m;if (x = l)int m = (l+r)/2;if (x = am) return m;if (x am) r = m+1;else l = m-1;return -1;答:错误if (x am) r = m+1; 当查找的元素在中间元素的左边时,右指针应该为 m-1 位置,修改成
2、 if (x l) int m = (l+r)/2;if (x = am) return m;if (x l) 要考虑到 数组只有一个元素的情况 所以应该是 r=l ;2、0(1)空间子数组环卫算法:设 a0:n-1是一个n维数组,k ( K k n-1 )是一个非负整数。试设计一个算法将子数组 a0 : k-1 与 ak+1 : n-1 换位。要求算法在最坏情况下 耗时0(n),且只用0(1)的辅助空间。答:最简单的方法就是循环 (n-k-1) 次,将 a 数组的末尾数字插入到 a0 之前。 具体做法:(1)首先开辟一个额外空间 temp 用于存放每一次 a 数组的末尾数据。(2)temp
3、- an-1(3)将 a0: n-2 每个数据都依次向后移动一位赋值给 a1: n-1 。(4)a0 - temp(5)循环执行 (2) -(4) 步 (n-k+1) 次。代价分析: 时间代价 0(n-1)*(n-k+1) 即0(nA2)数量级;空间代价: 0 (1)3、定义: 给定一个自然数 n,由n开始依次产生半数集 set(n)中的元素如下:1) n set(n) ;2)在 n 的左边加上一个自然数,但该自然数不能超过最近添加的数的一半;3)按此规则进行处理,直至不能再添加新的自然数为止。例如 set(n) 6,16,26,126,36,136 。其中共有 6 个元素。半数集问题:对于给
4、定的 n,求半数集set(n)中元素的个数。答:半数集 set(n) 中元素个数的求解是个递归的过程。设 set(n) 中的元素个数为 f(n) ,则 显然有递归表达式:f(n )=1+刀f(i) , i=1,2 n/2 。即半数集set (n)元素个数f(n)=1+f(1)+f(2)+.+f(floor(n/2). 用递推法求解。 C 语言代码如下:#include #includeint main()int n;int i,j,s;int buf106;char *in=input.txt,*out=output.txt;FILE *ip,*op;if(ip=fopen(in,r)=NUL
5、L)return 1; if(op=fopen(out,w)=NULL)return 2;fscanf(ip,%d,&n);fclose(ip);buf1=1;buf2=2;buf3=2;for(i=4;i*2=n;i+)s=1;for(j=1;j=i/2;j+)s+=bufj;bufi=s;s=1;for(j=1;j=n/2;j+)s+=bufj;fprintf(op,%d,s);fclose(op);/* system(pause);*/return 0;4、设计一个算法,找出由 n 个数组成的序列的最长单调递增子序列的长度。 答: #include #define m 10/ 快速排序v
6、oid QuickSort(int R,int s,int t) int i=s,j=t; int tmp;if(si&Rj=tmp) j-; Ri=Rj; while(ij&Ri=tmp) i+; Rj=Ri;Ri=tmp;QuickSort(R,s,i-1);QuickSort(R,i+1,t);/ 找出最长公共子序列void LCSLength(int x,int y,int n,int cmm,int bmm) int i,j; for(i=0;in;i+) c0i=0; ci0=0;for(i=0;in;i+) for(j=0;j=cij-1) cij=ci-1j;bij=2; el
7、se cij=cij-1; bij=3;void LCS(int i,int j,int *x,int bmm) if(i0|j0) return; if(bij=1) LCS(i-1,j-1,x,b); coutxi ; else if(bij=2) LCS(i-1,j,x,b);else LCS(i,j-1,x,b);void main() int xm,ym,d;cout 请输入元素个数 d;cout 请输入元素 endl;for(int i=0;ixi; yi=xi;int cmm=0,bmm=0;QuickSort(x,0,d-1);LCSLength(x,y,d,c,b);cout
8、 最长单调递增子序列为: endl; LCS(d-1,d-1,x,b);5、会场安排问题:假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。 设计一个有效的贪心算法进行安排。 对于给定的 n 个待安排的活动, 计算使用最少会场的个 数。每个活动 i 都有一个开始时间和结束时间,分别表示为 b(i) , f(i) 。答:#includeusing namespace std; #define M 50/ 最大活动数 struct Active int b;/ 开始时间int f;/ 结束时间int no;/ 预安排会场号aM;/ 两元素交换位置void swap(Active &a,
9、Active &b)Active t=a; a=b; b=t;void main() int k, i,j; cout 输入待安排活动数 :k; cout 输入待安排活动的开始时间和结束时间 :endl; / 输入活动时间 / 活动时间排序 for(i=1;i=k;i+) for(j=i;jaj.b) swap(ai,aj); if(ai.b=aj.b) if(ai.faj.f) swap(ai,aj);int int sum=1;/ 使用的会场数初始化int n; a1.no=sum; for(i=2;i=k;i+) for(n=1;ni;n+) if(an.no!=0&an.f=ai.b)
10、 ai.no=an.no; an.no=0;/ 已经安排过的活动就不再比较 break; if(n=i)sum+=1; ai.no=sum; cout 输出最少会场数 :nsumendl; system(pause);6、最优分解问题:设 n 是一个正整数。现要求将 n 分解为若干个互不相同的自然数的 和,使得这些自然数的乘积最大。设计一个算法,得到最优分解方案。分析:我们知道如果 a+b=常数,贝U |a-b|越小,a*b越大。贪心策略:将n分成从2开始的连续自然数的和。如果最后剩下一个数,将此数在 后项优先的方式下均匀地分给前面各项。答:void dicomp(int n, int a)i
11、nt k = 1;if (n 3) a1 = 0; return; if (n ak) k+;ak = ak - 1 + 1;n -= ak;if (n = ak) ak+; n-;for (int i = 0; i n; i+) ak - i+;7、子集和问题:设 S Xi,X2丄,Xn是n个正整数的集合,c是一个正整数。那么是否存 在S的一个子集S,使得子集中元素之和等于 c,即 x C。X S1答:#includeint n,c; int a100;int current100; / 存放当前选择的情况int best100; / 存放最后选择的子集合, besti=1 ,表示包含,反之
12、即不包含。int d=1; / 判断有无满足的情况int d2=0; / 是否已经选出子集和void Back(int m,int count);int main() int i,j;scanf(%d %d,&n,&c);for(i=0;in;i+) scanf(%d,&ai); currenti=besti=0;Back(0,0);if(d) printf(no solutionn); for(j=0;jn)return; if(count=c) d=0; / 有满足的子集和 if(d2) return 0; for(k=0;k 0 Xi = yi时 , cij =ci-1j-1 + 1当
13、i , j 0 Xi != yi时 , cij= maX cij-1 , ci-1j public class LSC private in t c,b;private int m,n;private char A,B;public LSC(char A,char B) this.A=A;this.B=B;m=A.length;n=B.length;c=new intm+1n+1; b=new intm+1n+1;for(int i=0;in+1;i+) c0i=0; for(int j=0;jm+1;j+) cj0=0;public LSC() public int LSCLength()
14、for(int i=1;im+1;i+) 是相等的话 */for(int j=1;j=cij-1) cij=ci-1j; bij=1;/* * 情况2 */else cij=cij-1; bij=2;return cmn;public void print(int i,int j) if(i=0|j=0) return; else if(bij=0) print(i-1,j-1); System.out.print(Ai-1); else if(bij=1) print(i-1,j); else print(i,j-1);public int LSCLength2(int i,int j) i
15、f(i0|ja2?a1:a2;public static void main(String args) char A=g,f,d,a,s,d,a,c;char B=g,c,f,a,t,0,c,c; LSC lsc=new LSC(A,B); System.out.println(lsc.LSCLength2(7,7);9、记矩阵连乘积 Ai, j %Ai Ai 1.Aj , i j 。 确定计算 A1:n 的最优计算次序,使得所需数乘的次数最少。1、说明矩阵连乘计算次序问题的最优解包含着其子问题的最优解, 即最优子结构性 质。2、该问题具备子问题的重叠性质。3、说明采用动态规划方法可以解决该问
16、题。4、设计该算法,分析算法的复杂性。答:计算 Ai:j 的最优次序所包含的计算矩阵子链 Ai:k 和 Ak+1:j 的次序也是最优的。设计算Ai:j , w i wj w n,所需要的最少数乘次数 mi,j,则原问 题的最优值为 m1,n当 i=j 时,Ai:j=Ai ,无需计算,因此,mi,j=O , i=1,2,,n当 ij 时,利用最优子结构性质计算 mi,j . 设 Ai:j 的最优次序在 Ak 和 Ak 1 之 间断开,则m :i,j= m :i,k:+ m “+1,门+ p i-i p k p j其中Ai的维数为pi-1 x pj k的位置只有j-i 种可能,i, i+1, ,j
17、-1,其中使计算量最小的那个位置 为最优解,数乘次数 mi,j 最小值为问题的最优值可以递归地定义 mi,j 为: 0 i=j m i,j = min m i , k + m k +1, j + p i-1 p kp j ij 将最优值 mi j 对应的断开位置记为 si j ,则可递归的由 si j 构造出相应的最优 解 对于 1 w i w j w n 不同的有序对 (i,j) 对应于不同的子问题。 因此, 不同子问题的 个数最多 只有由此可见,在递归计算时,许多子问题被重复计算多次。这也是该问题可用动态 规划算法求解的又一显著特征。 用动态规划算法解此问题, 可依据其递归式以自底向上的方
18、式进行计算。在计算 过程中,保存已解决的子问题答案。每个子问题只计算一次,而在后面需要时只 要简单查一下,从而避免大量的重复计算最终得到多项式时间的算法matrixchain 已经记录了构造最优解所需的全部信息。从s1n 可知,计算A1:n的最优加括号方式为(A 1 : s1n)(As1n+1: n) 计算A 1 : s1n 的最优加括号方式为(A 1 :s1s1n )(A s1s1n +1 : s1n)10、考虑分数背包问题,定义如下:给出 n个大小为s i, s 2,s n ,价值为vi, v 2,nVn的物品, 并设背包容量为 C,要找到非负实数X1, X 2,X n,使和 XiVi在约
19、束n i 1Xisi C下最大。写出求解问题的贪心算法,估计算法的时间复杂性。i 1答:从问题的某一初始解出发;while能朝给定总目标前进一步do求出可行解 的一个解元素;由所有解元素组合成问题的一个可行解; 从问题的某一个初始 解出 发逐步逼近给定的目标, 以尽可能快的地求得更好的解。当达到某算法中 的某一 步不能再继续前进时,算法停止。 #inelude #define total10 float ptotal,wtotal,ttotal; void greedy_knaPsack(int X,int c) int note,i; float max; while(1) note=0;
20、max=0; for(i=0;ix;i+) if(maxpi/wi) &(ti=0) max=pi/wi; note=i; if(wnotec) tnote=1; c-=wnote; else tnote=c/wnote; break; int main() int i=0,n=0; float cu; printf( 请输入物品总数(不大于 %d与背包的容量:,total); while(1) scanf(%d%f,&n,&cu); if(ntotal) break; else printf( 物品总数超出范围,请 重新 输入:); printf( 请输 入每个物 品的价值 与重量: n); for(i=0;in;i+) scanf(%f%f,&pi,&wi); ti=0; greedy_knaPsack(n,cu); printf( 由 贪 心 算 法 所 得 最 优 解 是 : n); for(i=0;in;i+) printf(%f ,ti); return 0; 时间复杂度分析: 算法中用到三个 for 循环,故计算时间复杂度: O(n)=n+n+n=3n 即此算法的时间复 杂度为: O(n)=n
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1