《算法分析与设计》作业答案

  • 格式:doc
  • 大小:332.00 KB
  • 文档页数:15

《算法分析与设计》作业1、考虑,10≤≤i x 而不是x i ∈{0,1}的连续背包问题。

一种可行的贪婪策略是:按价值密度非递减的顺序检查物品,若剩余容量能容下正在考察的物品,将其装入;否则,往背包内装如此物品的一部分。

(a) 对于n=3,w=[100,10,10],p=[20,15,15],以及c=105,上述装入法获得结果是什么?(b)证明这种贪婪算法总能获得最优解。

(c) 用伪代码描述此算法。

答:(a )利用贪婪算法,按价值密度考察的背包为w2,w3,w1;背包w2和w3重20,还可以容纳85,由于10≤≤i x ,背包w1还可以装入x1=0.85,则背包内物品总价值为15+15+20*0.85=47.(b )假设已按价值密度排好序,考察w1,w2,……,wi ,……,对应的价值为p1,p2,……,pi,……如果装到pi-1再装pi 时,恰好要取xi 个wi 。

(,10≤≤i x ) 因为比它价值密度大的都已装载完,所以此时获得的为最优解。

(c )算法描述如下: template <class T>int ContainerLoading( int x[], T w[], T c, int n ) {int *t = new int[n+1]; IndirectSort(w, t, n); for( int i=1; i<=n; i++) x[i] = 0;for(i=1; i<=n && w[t[i]]<=c; i++){ x[t[i]] = 1; c += w[t[i]]; } delete []t; }2、证明当且仅当二分图没有覆盖时,下述算法找不到覆盖。

m=0; //当前覆盖的大小对于A中的所有i,New[i]=Degree[i]对于B中的所有i,Cov[i]=falsewhile(对于A中的某些i,New[i]>0) {设v是具有最大的New[i]的顶点;C[m++]=v;for(所有邻接于v的顶点j) {If(!Cov[j]) {Cov[j] = true;对于所有邻接于j的顶点,使其New[k]减1}}}if (有些顶点未被覆盖) 失败else 找到一个覆盖2)给出一个具有覆盖的二分图,使得上述算法找不到最小覆盖。

证明:如果二分图有覆盖,则通过以上贪婪算法,总能得到最小覆盖A’。

首先假定A’为空集当更多的顶点可被覆盖时,把能覆盖未被覆盖的顶点数目最多的顶点加入A’如果有些顶点未被覆盖,则失败,否则总能找到一个覆盖。

所以只有当二分图没有覆盖时,才会失败而找不到覆盖,否则总能找到一个覆盖A’。

2)令S= {S1,. . .,S5 },U= { 4,5,. . .,15},S1 = { 4,6,7,8,9,1 3 },S2 = { 4,5,6,8 },S3 = { 8,1 0,1 2,1 4,1 5 },S4 = { 5,6,8,1 2,1 4,1 5 },S5 = { 4,9,1 0,11 }。

通过以上算法,得S ' = {S1,S2,S4,S5 }实际最小覆盖为{S1,S4,S5 }3、对于二分图覆盖问题设计另一种贪婪启发算法,贪婪准则是:如果B中某一个顶点被A中一个顶点覆盖,选择A中这个顶点;否则,从A中选择一个顶点,使得它所覆盖的未被覆盖的顶点数目最多。

给出这种贪婪算法的伪代码。

解答:贪婪算法的伪代码为:m=0 // 当前覆盖的大小对于A 中的所有i, Out[i]=outdegree[i];对于B 中的所有i, In[i]=indegree[i];对于B 中的所有i, Cov[i]=false;for (对于B中所有入度为1的顶点i) {设v是邻接于B[i]的顶点C[m++]=v;for (所有邻接于v的顶点j) {if (!Cov[j]) { Cov[j]=true;对于所有邻接于j的顶点,使其Out[k]减1} } }while (对于A 中的某些i, Out[i]>0) {设v是具有最大Out[i]的顶点C[m++]=v;for (所有邻接于v的顶点j) {if (!Cov[j]) { Cov[j]=true;对于所有邻接于j的顶点,使其Out[k]减1} } }if (有些顶点未被覆盖) 失败else 找到一个覆盖4、有n个硬币,其中1个是假币,且假币较轻。

请用分而治之方法设计一个找出假币的算法。

1)用伪代码描述你的算法;2)用C程序描述你的算法;3)分析你的算法的时间复杂性。

解答:代码如下Feit_money(low, high) // 假定伪币较真币轻{float mid;if high-low=1 thenif A[low]<A[high] then return A[low];else if A[low]>A[high] return A[high];elsemid=(low+high)/2;if (high-low+1)%2==0 thensum1=sum(low, mid);sum2=sum(mid+1, high);elsesum1=sum(low, mid-1);sum2=sum(mid+1, high);end ifif sum1=sum2 then return A[mid];else if sum1<sum2 then(high-low+1)%2==0? Feit_money(low, mid) : Feit_money(low, mid-1);elseFeit_money(mid+1, high);end ifend ifreturn 0;}其时间复杂度为:O(log n).用分而治之算法计算4823*9715;2)假设两个大整数都是n=2k位,请用伪代码描述两个大整数乘积的分而治之算法。

解答:1) 设X=4823, Y=9715,用上述算法计算XY的计算过程可列表如下,其中带'号的数值是在计算完成AC,BD,和(A-B)(D-C)之后才填入的。

X=4823 A=48 B=23 A-B=15Y=9715 C=97 D=15 D-C=82AC=(1643)' BD=(1107)' (A-B)(D-C)=(260)'XY=(4496)'104+[(4496)'+(345)'+(1230)']102 +(345)'=(45567445)'进一步拆分A=48 A1=4 B1=8 A1-B1=-4C=97 C1=9 D1=7 D1-C1=2A1C1=36 B1D1=56 (A1-B1)(D1-C1)=-8AC=3600+(36+56-8)10+56=4496B=23 A2=2 B2=3 A2-B2=-1D=15 C2=1 D2=5 D2-C2=4A2C2=2 B2D2=15 (A2-B2)(D2-C2)=-4BD=200+(2+15-4)10+15=345|A-B|=15 A3=1 B3=5 A3-B3=-4 |D-C|=82 C3=8 D3=2 D3-C3=-6 A3C3=8 B3D3=10 (A3-B3)(D3-C3)=24 (A-B)(D-C)=800+(8+10+24)10+10=1230 2)mul(x, y, n) {if (2<=n && x!=0 && y!=0) { k=n/2;p = power(10, k); b= x % p; a=x/p; d=y % p; c=y/p;ac=mul(a, c, k); bd=mul(b, d, k);mix=mul(a-b, d-c, k);return (ac*p+(mix+ac+bd)*p+bd); }else if (x==0||y==0) return 0;else x*y; }该算法的运行时间满足的递归方程为: , 计算得其时间复杂度为:T(n)=O(3log2n)。

7、设计一个分而治之算法来计算二叉树中分支结点的个数。

请用伪代码描述你的算法。

请分析算法的时间复杂度。

解答:算法伪代码如下:int MaxSubSum(int a, int left, int right) { int sum=0;if (left==right)sum=a[left]>0?a[left]:0; else{int center=(left+right)/2;int leftsum=MaxSubSum(a,left,center);int rightsum=MaxSubSum(a,center+1,right); int s1=0;lefts=0;for (int i=center;i>=left;i--) { lefts+=a[i];if (lefts>s1) s1=lefts; }int s2=0;rights=0;for (int i=center+1;i<=right;i++) { rights+=a[i];if (rights>s2) s2=rights; }sum=s1+s2;11)()2/(3)1()(>=⎩⎨⎧+=n n n O n T O n Tif (sum<leftsum) sum=leftsum;if (sum<sightsum) sum=rightsum;}return sum;}算法时间复杂度为:8、货物装箱问题:设有一艘货船装货箱。

共有n=6件货箱,它们的重量如下表示:[w1,…, w6] = [100, 200, 50, 90, 50, 20],船的限载重量是c=300。

试用贪婪算法装船,要求货箱装得最多。

贪婪准则:从剩下的货箱中选择重量最小的货箱。

1)请给出问题的解;2)对一般的n,重量为w=[w1,…, wn],船的限载重量是c>0,要求船的货箱装得最多,请用伪代码描述你的算法;3)考虑有两条船的情况,即有两条船,船的限载重量是分别是c1和c2;共n件货箱,重量为w=[w1,…, wn],试用贪婪算法装船,要求两条船的货箱装得最多。

请描述你的算法,该算法总能产生最优解吗?请说明你的理由。

解答:1)货箱按重量从小到大排列,得{20,50,50,90,100,200}.根据选择最小重量货箱的贪婪准则,则准箱顺序为{w6,w3,w5,w4,w1,w2},因为船限载重量c=300,故实际装箱为w6,w3,w5,w4共4个货箱重210。

2)算法如下template <class T>int ContainerLoading( int x[], T w[], T c, int n ){ i nt *t = new int[n+1];IndirectSort(w, t, n);//对重量按间接寻址方式排序for( int i=1; i<=n; i++) x[i] = 0;for(i=1; i<=n && w[t[i]]<=c; i++){ x[t[i]] = 1; //t[i]是间接寻址表c -= w[t[i]]; }delete t[];}3)伪代码如下:void knapsack(int v[ ], int w[ ], int c, int m[ ][ ]) { int n=v.length-1;int jMax=min(w[n]-1,c);for( int j=0; j<=jMax; j++) m[n][j]=0;for( int j=w[n]; j<=2*w[n]-1; j++) m[n][j]=v[n];for( int j=2*w[n]; j<=c; j++) m[n][j]=2*v[n];for( int i=n-1; i>1; i--) { jMax=min(w[i]-1,c);for( int j=0; j<=jMax; j++) m[i][j]=m[i+1][j];for(int j=w[i]; j<=2*w[i]; j++)m[i][j]=max(m[i+1][j], m[i+1][j-w[i]]+v[i]);for(int j=2*w[i]; j<=c; j++)m[i][j]=max(m[i+1][j], m[i+1][j-w[i]]+v[i], m[i+1][j-2*w[i]]+2*v[i] ); }m[1][c]=m[2][c]; if (c>=2*w[1])m[1][c]=max(m[1][c], m[2][c-w[1]]+v[1], m[2][c-2*w[1]]+2*v[1]); else if (c>=w[1])m[1][c]=max(m[1][c], m[2][c-w[1]]+v[1]);} 显然,该算法能产生最优解。