算法分析与设计作业(2)

2019-04-02 11:31

算法分析题:

1.1求下列函数的渐近表达式:

?(n)=3n2. T(n)=3n2?10n的渐近表达式T?(n)=2n. T(n)=n2/10?2n的渐近表达式为T?(n)=21. T(n)=21+1/n的渐近表达式为T?(n)=3logn. T(n)=logn3的渐近表达式为T?(n)=log3?10n. T(n)=10log3n的渐近表达式为T1.2试论O(1),O(2)的区别。

因为: O(1)+O(1)=O(1?1)=O(2) O(1)+O(1)==O(1). 所以,O(1),O(2)应该是相等的。

2n2/31.3 按照渐近阶从低到高的顺序排列以下表达式:4n,logn,3,20n, 2,n.又

n!应该排在哪一位?

从低到高:2,logn,20n,n2/3,4n,3,n!

2n2.2 下面的7个算法与本章中的二分搜索算法Binary Search略有不同。请判断这7个算法的正确性。如果算法不正确,请说明产生错误的原因。如果算法正确,请给出算法的正确性证明

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;

不正确,当循环进行到只有两个元素的时候,int middle=(left+right)/2,就等于那个较

小的元素位置。这时如果X大于较小的元素的时候,即if(x>a[middle])left=middle;就造成了下次循环还是两个元素,这就形成了死循环。

当循环进行只有一个元素的时候,若X不等于这个元素,无论是大还是小,left,

middle,right的值都一样,都会继续进行循环,这也是死循环。

页 6

2. while(left

是while(left

元素的时候,middle=(left+right)/2为第二个元素,left=middle,则下一步是三个元素),则

不正确,当x等于最后一个最大的此次循环执行完毕时,只有最后两个元素,

元素的时候,循环中的if(x

******************************************************************************* 3. while(left+1!=right) 不正确,当x=最大元素的时候,因

{ int middle=(left+right)/2;

if(x

}if(x==a[left])return left; return -1;

{ int middle=(left+right)/2; if(x>=a[middle])left=middle; else right=middle;

}

if(x==a[left])return left; return -1;

为循环的条件是left+1!=right,循环到最大的两个元素的时候跳出,但接下来只拿这两个元素的左元素和X做比较,做出了误判。

******************************************************************************* 4. if(n>0&&x>=a[0]) 不正确,当循环至两个元素时,

{ int left=0,right=n-1;

middle=(left+right)/2为左元素,若x=右元素, while(left

{ int middle=(left+right)/2;

则执行left=middle,陷入死循环。

if(x

}

if(x==a[left])return left;

}

return -1;

******************************************************************************* 5. if(n>0&&x>=a[0])

{ int left=0,right=n-1; s1?s2?s,其中s1s2为s的子集。那么

while(left

{ int middle=(left+right+1)/2; if(x

} if(x==a[left])return left;

}return -1;

x?s?x?s1或者x?s2。若有方法判定x?s1还是x?s2,就能够进行循环,直到

这个是正确的,正确性证明:x是集合s中的一个元素,s中有n个元素,

找到该元素为止。算法中正是此情况,所以是正确的。

*******************************************************************************6. if(n>0&&x>=a[0]) 不正确,因为这个算法实际上是把s

{ int left=0,right=n-1; while(left

{ int middle=(left+right+1)/2; if(x

if(x==a[left])return left;

}

return -1;

分为了3部分,s1,a[middle],s2.当x< a[middle]时,它属于s1是正确的,但x>=a[middle]时,它不一定属于s2

******************************************************************************* 7. if(n>0&&x>=a[0]) 不正确,只有两个元素的时候,

{ int left=0,right=n-1;

middle为第二个元素。If语句成立的时候, while(left

{ int middle=(left+right+1)/2;

right=middle,相当于没有变化,这就陷入 if(x

else left=middle; 了死循环。 }

if(x==a[left])return left;

}

return -1;

页 7

2.26试说明如何修改快速排序算法,使它在最坏情况下的计算时间为O(nlogn)。

答:完全保证使快速排序算法在最坏情况下的计算时间为O(nlogn)是很困难的,但可以采用一些办法来消除算法的退化结构,比如课本上的随机选择策略,以及我要说的平衡快速排序。

鉴于在平时生活中的数据排序,其数据往往带有规律性。在中值的选择策略上,我们比较一下第一个,最后一个,以及中间一个的值,以这3个值中位于中间的那个来进行划分,这样就能使快速排序避免了大多数的最坏情况,即使是对于两边小中间大的特殊情况,这个方法也有其作用——在第一遍排序时打乱这个特殊情况。因此,这个算法在实际运用中是比较好的一种快速排序。

算法如下:

template

int partition (Type a[],int p,int r) { int i=p,j=r+1; }

int BalancePartion(Type a[],int p,int r) { int i,m;

m=(p+r)/2; switch(1) Type x=a[p]; while(1)

{ while(a[++i]

while(a[--j]>x); if(i>=j)break; Swap(a[i],a[j]);

}

void BalanceQuickSort(Type a[],int p,int r) { if(p

{ int q=BalancePartition(a,p,r); }

BalanceQuickSort(a,p,q-1); BalanceQuickSort(a,q+1,r); }

Swap(a[i],a[p]); return Partition(a,p,r);

{ case(a[p]<=a[m]&&a[p]>=a[r])

||(a[p]>=a[m]&&a[p]<=a[r]):i=p;break;

case(a[m]<=a[p]&&a[m]>=a[r])

||(a[m]>=a[p]&&a[m]<=a[r]):i=m;break;

case(a[r]<=a[m]&&a[r]>=a[p])

||(a[r]>=a[m]&&a[r]<=a[p]):i=r;break;

3.5给定n种物品和一背包。物品i的重量是wi,体积是bi,其价值为vi,背包的容量为c,容积为d。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大?在选择装入背包时,对每种物品i只有两种选择,即装入背包或者不装入背包。不能将物品i装入背包多次,也不能只装入部分的物品i。试设计一个解此问题的动态规划算法,并分析算法的计算复杂性。

算法如下:

页 8

int MaxValue(int n,int c,int *w,int d,int *b,int *v,int ***m) {

int t = max(w[n],b[n]);

for(int i = 1;i

for( int j = 1;j

else{x[i]=1;c-=w[i];d-=b[i];} for(int j = t;j1;i--) x[n]=(m[n][c][d])?1:0; {

} t = max(w[i],b[i]);

for(int j1 = 1;j1

for(int k1 = 1;k1

m[i][j1][k1] = m[i+1][j1][k1];

for(int j1 = t;j1<=c;j1++)

for(int k1 = t;k1<=d;k1++)

m[i][j1][k1] = max(m[i+1][j1][k1],

m[i+1][j1-w[i]][k1-b[i]]+v[i]);

}

m[1][c][d] =max( m[2][c][d],

m[2][c-w[1]][d-b[1]]+v[1]);

return m[1][c][d];

}

5.4试设计一个解最大团问题的迭代回溯法。

我设计的算法如下:

int n=1,k;//n放的是最大团的点个数,k放的不同最大团的个数。 int q[MAX][MAX];

int backtrack(int *p,int a,int b); {//p[]中存放的是图中各点的序号 if(b-a<1)return 0; if(b-a=1){ if(p[a]p[b]无边相连)return 0; else {if(n=1)n++;return 1;} } for(int i=a;i<=b;i++) { swap(p[a],p[i]); if(backtrack(p,a+1,b)) { if(判断p[a]和p[a+1~b]都有边)//************************* { if(b-a+1>n;) { n++; k=0; for(int j=0;j<=n;j++)q[0][j]=p[a+j]; } else if(b-a+1=n)//&&&&&&&&&&& { for(int j=0;j

页 9

算法实现题:

2.2 众数问题。

给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称之为众数。

算法设计:对于给定的由n个自然数组成的多重集S,计算S的众数及其重数。

数据输入:输入数据由文件名为input.txt的文本文件提供。文件的第一行为多重集S中元素个数n;在接下来的n行中,每行有一个自然数。

结果输出:将计算结果输出到文件output.txt。输出文件有2行,第1行是众数,第2行是重数。

我的递归算法实现如下:

#include #define MAX 10 int x=0;

int mode(int *p,int a) { int i,j,k[MAX],m=0,n=0;

//m为删除的个数,n为保留的个数,k[a]为删除的数的记录。 }

if(a==0)return p[0]; x++;

if(a==1)return p[0]; for(i=0;i

{ for(j=0;j

return mode(p,n);

if(j==m) {m++;k[m-1]=p[i];}

//在已删除个数字里找不到p[i],则删除它。 else{n++;p[n-1]=p[i];}

int main(void) { }

int i,a,b[MAX]; FILE *fp1,*fp2;

fp1=fopen(\,\); fp2=fopen(\,\); fscanf(fp1,\,&a);

for(i=0;i

3.2最小硬币问题。

算法设计:对于给定的1<=n<=10,硬币面值数组T和可以使用的各种面值的硬币个数数组Coins,以及钱数m,0<=m<=20001,计算找钱的最少硬币数。硬币的面值存于T[]中,个数存于Coins[]中。

数据输入:input.txt提供输入数据,文件的第1行中只有1个整数给出的n的值,第2行起每行2个数,分别是T[j]和Coins[j]。最后1行使要找的钱数m。

结果输出:将计算出的最少硬币数输出到文件output.txt。问题无解时输出-1。

答:由于硬币的面值其实是一组特殊值,(10)>=2*(5)>=2*2*(2)>=2*2*2*(1).因此,使用贪心算法可以很简便的算出问题答案。但是我们要考虑的是,假设硬币的面值可以为任何值,比如,7,16,等等,这时就不能使用贪心算法,我采用动态规划来解决这个问题。令T[]的值有序排列,当只用面值小于等于T[i]的硬币时,可找钱j的最少硬币数为n[i][j],则p[i][j]满足递归p[i][j]= min(p[i-1][j], p[i-1][j-k*T[i]]+k), 其中递归在K的循环for(k=1;k<=Coins[i];k--)中,来判别是否有足够的该面值的硬币可以使用。

页 10


算法分析与设计作业(2).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:心理健康主题班会记录(共6篇)

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: