西工大算法复习资料总结最终修订版.docx

上传人:b****6 文档编号:4015751 上传时间:2022-11-27 格式:DOCX 页数:35 大小:112.85KB
下载 相关 举报
西工大算法复习资料总结最终修订版.docx_第1页
第1页 / 共35页
西工大算法复习资料总结最终修订版.docx_第2页
第2页 / 共35页
西工大算法复习资料总结最终修订版.docx_第3页
第3页 / 共35页
西工大算法复习资料总结最终修订版.docx_第4页
第4页 / 共35页
西工大算法复习资料总结最终修订版.docx_第5页
第5页 / 共35页
点击查看更多>>
下载资源
资源描述

西工大算法复习资料总结最终修订版.docx

《西工大算法复习资料总结最终修订版.docx》由会员分享,可在线阅读,更多相关《西工大算法复习资料总结最终修订版.docx(35页珍藏版)》请在冰豆网上搜索。

西工大算法复习资料总结最终修订版.docx

西工大算法复习资料总结最终修订版

笔试部分

1.简答题(40分)

1.算法的基本概念、性质及其与程序的联系与区别

算法:

是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令。

算法性质:

输入---有零个或者多个外部量作为算法的输入;

输出---算法产生至少一个量最为输出;

确定性:

组成算法的每条指令是清晰的、无歧义的;

有限性:

算法中指令的执行次数有限和执行的时间有限。

程序:

是算法用某种设计语言的具体实现,程序可以不满足算法的有限性。

2.大O表示法的含义和渐进时间复杂度(要会计算复杂度)

大O表示法:

称一个函数g(n)是O(f(n)),当且仅当存在常数c>0和n0>=1,对一切n>n0均有|g(n)|<=c|f(n)|成立,也称函数g(n)以f(n)为界或者称g(n)囿于f(n)。

记作g(n)=O(f(n))。

定义:

如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数。

T(n)称为这一算法的“时间复杂度”。

当输入量n逐渐加大时,时间复杂度的极限情形称为算法的“渐近时间复杂度”。

3.分治法的基本思想是什么

分治法的基本思想是:

将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。

递归地解这些子问题,然后将各子问题的解合并得到原问题的解。

4.回溯算法的基本思想及其一般模式(子集树+排列树)

基本思想:

在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。

当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。

若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。

而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

搜索子集树的一般模式:

voidsearch(intm)

{

if(m>n)//递归结束条件

output();//相应的处理(输出结果)

else

{

a[m]=0;//设置状态:

0表示不要该物品

search(m+1);//递归搜索:

继续确定下一个物品

a[m]=1;//设置状态:

1表示要该物品

search(m+1);//递归搜索:

继续确定下一个物品

}

}

搜索排列树的一般模式:

voidsearch(intm)

{

if(m>n)//递归结束条件

output();//相应的处理(输出结果)

else

for(i=m;i<=n;i++)

{

swap(m,i);//交换a[m]和a[i]

if()

if(canplace(m))//如果m处可放置

search(m+1);//搜索下一层

swap(m,i);//交换a[m]和a[i](换回来)

}

}

5.动态规划的基本思想、基本步骤、基本要素是什么

基本思想:

将待求解问题分解成若干子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

基本步骤:

①找出最优解的性质,并刻画其结构特征;

②递归地定义最优值;

③以自底向上的方式计算出最优值;

④根据计算最优值时得到的信息,构造最优解。

基本要素:

最优子结构性质和子问题重叠问题

6.什么是最优子结构性质和子问题重叠性质

最优子结构性质:

如果问题的最优解所包含的子问题的解也是最优的,则称该问题具有最优子结构性质(即满足最优化原理)。

最优子结构性质为动态规划算法解决问题提供了重要线索。

 

子问题重叠性质:

指在用递归演算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。

动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

 

7.分治法与动态规划的联系与区别

联系:

基本思想相同,即将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

区别:

适用于动态规划法求解的问题,经分解得到的子问题往往不是相互独立的。

分治法子问题被重复计算多次,而动态规划子问题可用一个表来记录已解决子问题的答案,避免了子问题重复计算的问题。

8.动态规划的变形(备忘录方法)与动态规划的联系与区别

联系:

都用表格保存已解决的子问题的答案

区别:

备忘录方法的递归方式是自顶向下的,而动态规划的递归方式是自底向上的。

9.分支限界法(广度优先搜索)的基本思想是什么

分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。

在分支限界法中,每一个活结点只有一次机会成为扩展节点。

活结点一旦成为扩展节点,就一次性产生所有儿子节点。

在这些儿子节点中,导致不可行解或导致非最优解的儿子节点被舍弃,其余儿子节点被加入活结点表中。

此后,从活结点表中取下一节点成为当前扩展节点,并重复上述节点扩展过程,这个过程一直持续到找到所需的解或活结点表为空时为止。

10.分支限界法与回溯法的区别

1.搜索方式不同:

分支限界法使用广度优先或最小消耗优先搜索,而回溯法使用深度优先搜索。

2.主要区别:

在于它们对当前扩展节点所采用的扩展方式不同。

分支限界法:

每个节点只有一次成为活结点的机会

回溯法:

活结点的所有可行子节点被遍历后才被从栈中弹出

11.搜索算法的一般模式

搜索算法关键要解决好状态判重的问题:

voidsearch()

{

open表初始化为空;

起点加入到open表;

while(open表非空)

{

取open表中的一个结点u;

从open表中删除u;

for(对扩展结点u得到的每个新结点vi)

{

if(vi是目标结点)

输出结果并返回;

If(notused(vi))

vi进入open表;

}

}

}

12.贪心算法的基本思想、基本步骤及基本要素

基本思想:

贪心算法总是做出在当前看来是最好的选择,即贪心算法并不从整体最优上加以考虑,所做的选择只是在某种意义上的局部最优选择,即贪心选择。

基本步骤:

①从问题的某个初始解出发;

②采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个局部最优解缩小问题的规模;

③将所有局部最优解综合起来,得到原问题的解。

基本要素:

①贪心选择性质:

指所求问题的整体最优解可以通过一系列的局部最优的选择,即贪心选择来达到。

贪心选择策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

②最优子结构性质:

一个问题的最优解包含其子问题的最优解。

13.贪心算法与动态规划算法联系与区别

联系:

都要求问题具有最优子结构性质,即一个问题的最优解包含其子问题的最优解。

区别:

①在动态规划算法中,每步所做的选择往往是依赖于相关子问题的解,因而只有在解出相关子问题后,才能做出选择。

而在贪心算法中,仅在当前状态下做出最好的选择,即局部最优选择,然后再去解做出这个选择后产生的相应的子问题。

②动态规划算法通常以自底向上方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式做出相机的贪心选择以简化问题规模。

 

2.设计题(60分---写出核心代码或伪代码和相关的变量声明)

1.用二分查找算法查找某一个元素在线性表中的位置。

此问题的输入是待查元素x和线性表L,输出为x在L中的位置或者x不在L中的信息。

最直接的做法就是一个一个地扫描L的所有元素,直到找到x为止。

这种方法对于有n个元素的线性表在最坏的情况下需要n次比较。

一般来说,若没有其他的附加信息,在有n个元素的线性表中查找一个元素在最坏情况都需要n次比较。

考虑最简单的情况,该线性表为有序表,设其按照主键的递增顺序从小到大排列。

核心伪代码:

functionBinarySearch(L,a,b,x)

begin

ifa>bthenreturn-1

elsebegin

m=(a+b)div2;

ifx=L[m]thenreturn(m)

elseifx>L[m]

thenreturnBinarySearch(L,m+1,b,x);

else

returnBinarySearch(L,a,m-1,x);

end;

end;

2.请采用快速排序算法为下列数字排序,并写出最终结果(21254925*1608)

快速排序的基本思想:

选定一个基准值元素,对带排序的序列进行分割,分割之后的序列一部分小于基准值元素,另一部分大于基准值元素,再对这两个分割好的子序列进行上述的过程。

voidswap(inta,intb){intt;t=a;a=b;b=t;}

intPartition(int[]arr,intlow,inthigh)

{

intpivot=arr[low];//采用子序列的第一个元素作为基准元素

while(low

{

//从后往前在后半部分中寻找第一个小于基准元素的元素

while(low=pivot)

{

--high;

}

//将这个比枢纽元素小的元素交换到前半部分

swap(arr[low],arr[high]);

//从前往后在前半部分中寻找第一个大于基准元素的元素

while(low

{

++low;

}

//将这个基准元素大的元素交换到后半部分

swap(arr[low],arr[high]);

}

returnlow;//返回基准元素所在的位置

}

voidQuickSort(int[]a,intlow,inthigh)

{

if(low

{

intn=Partition(a,low,high);

QuickSort(a,low,n);

QuickSort(a,n+1,high);

}

}

3.写出对下面的序列进行归并排序的过程(从小到大)(631499823481570)

核心代码:

voidMergeSort(intlow,inthigh)

{

if(low>=high)//每个子列表中剩下一个元素时停止

return;

//将列表划分成相等的两个子列表,若有奇数个元素,则在左边子列表大于右边子列表

else

intmid=(low+high)/2;

MergeSort(low,mid);//递归划分子列表

MergeSort(mid+1,high);//递归划分子列表

//新建一个数组b用于存放归并的元素

int[]b=newint[high-low+1];

//两个子列表进行排序归并,直到两个子列表中的一个结束

for(inti=low,j=mid+1,k=low;i<=mid&&j<=high;k++)

{

if(arr[i]<=arr[j])

{

b[k]=arr[i];

i++;

}

else

{

b[k]=arr[j];

j++;

}

}

for(;j<=high;j++,k++)

//如果第二个子列表中仍然有元素,则追加到新列表

b[k]=arr[j];

for(;i<=mid;i++,k++)

//如果第一个子列表中仍然有元素,则追加到新列表

b[k]=arr[i];

for(intz=0;z

//将排序的数组b的所有元素复制到原始数组arr中

arr[z]=b[z];

}

4.装载问题

问题关键在于:

首先将第一艘船尽可能装满且c1<最大值max,然后将剩余的部分装上第二艘船c2,若:

总重量-c1

关键代码:

intc1,c2,n,w[10];

intweight=0,max=0;

voidsearch(intm)

{

if(m==n)

{

if(weight<=c1)

if(weight>max)

max=weight;

}

else

{

if(weight+=w[m]<=c1)

{

weight+=w[m];

search(m+1);

weight-=w[m]

}

search(m+1);

}

}

5.01-背包问题(回溯法)

关键代码:

intn,c;

intw[1000],v[1000];

inta[1000],max=0;

voidsearch(intm)

{

if(m>=n)

checkmax();

else

{

a[m]=0;

search(m+1);

a[m]=1;

search(m+1)

}

voidcheckmax()

{

inti;

intweight=0,value=0;

for(i=0;i

{

if(a[i]==1)

{

weight+=w[i];

value+=v[i];

}

}

if(weight<=c)

if(value>max)

max=value;

}

6.循环赛日程表(递归与分治)

设计思想:

按分治策略,可以将所有选手对分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。

递归地用这种一分为二的策略对选手进行分割,直至只剩下两个选手时,比赛日程表的指定就很简单了。

核心代码:

intN=1;

voidUpRightCopy(intn,intarray[])

{

for(inti=0;i

{

for(intj=n;j<2*n;j++)

{

array[N*i+j]=2*n+1-array[N*i+2*n-1-j];

}

}

}

voidDownRightCopy(intn,intarray[])

{

for(inti=n;i<2*n;i++)

{

for(intj=n;j<2*n;j++)

{

array[N*i+j]=array[N*(i-n)+j-n];

}

}

}

voidLeftDownCopy(intn,intarray[])

{

for(inti=n;i<2*n;i++)

{

for(intj=0;j

{

array[N*i+j]=array[N*(i-n)+j+n];

}

}

}

voidturn(intn,intarray[])

{

if(n==1)

array[0]=1;

else

{

turn(n/2,array);

DownRightCopy(n/2,array);

UpRightCopy(n/2,array);

LeftDownCopy(n/2,array);

}

}

7.最长公共子序列

核心代码:

chara[201],b[201];

intn1,n2;

voidsearch()

{

intList[201][201];

for(inti=0;i<=n1;i++)

List[i][0]=0;

for(intj=0;j<=n2;j++)

List[0][j]=0;

for(inti=1;i<=n1;i++)

{

for(intj=1;j<=n2;j++)

{

if(a[i-1]==b[j-1])

List[i][j]=List[i-1][j-1]+1;

else

{

if(List[i-1][j]>List[i][j-1])

List[i][j]=List[i-1][j];

else

List[i][j]=List[i][j-1];

}

}

}

8.矩阵连乘问题

核心代码:

intn;

intp[11];

voidsearch()

{

inta[11][11],temp;

for(inti=1;i<=n;i++)

a[i][i]=0;

for(intd=1;d<=n-1;d++)

{

for(inti;i<=n-d;i++)

{

intj=i+d;

a[i][j]=0+a[i+1][j]+p[i-1]*p[i]*p[j];

for(intk=i+1;k

{

temp=a[i][k]+a[k+1][j]+p[i-1]*p[k]*p[j];

if(temp

a[i][j]=temp;

}

}

}

}

9.用备忘录算法实现计算Fibonacci数列

核心代码:

intFib(intn)

{

intresult[n]={0,0,...,0};

intf1,f2;

if(n<2)

returnn;

if(result[n-1]==0)

f1=Fib(n-1);

else

f1=result[n-1];

if(result[n-2]==0)

f2=Fib(n-2);

else

f2=result[n-2];

result[n]=f1+f2;

return(f1+f2);

}

设计一个的高效算法实现Fibonacci数列

Version1(效率最差)

1.long Fibonacci(int n)   

2.{   

3.  if (n == 0)   

4.      return 0;   

5.  else if (n == 1)   

6.      return 1;   

7.  else if (n > 1)   

8.       return Fibonacci (n - 1) + Fibonacci (n - 2);   

9.  else   

10.       return -1;   

11.}  

Version2(效率其次)

1.long Fibonacci2(int n)   

2.{   

3.  if (n == 0)   

4.     return 0;   

5.  else if (n == 1)   

6.    return 1;   

7.  else if (n > 1)   

8.  {   

9.  

10.    if(tempResult[n] !

= 0)   

11.      return tempResult[n];   

12.    else   

13.    {   

14.          tempResult[n] = Fibonacci2 (n - 1) + Fibonacci2 (n - 2);   

15.          return tempResult[n];   

16.     }   

17.   }   

18.}  

Version3(效率最高---放弃递归用循环实现)

1.long Fibonacci3(int n)   

2.{   

3.  long * temp = new long[n + 1];   

4.  

5.  temp[0] = 0;   

6.  

7.  if (n > 0)   

8.     temp[1] = 1;   

9.  

10.   for(int i = 2; i <= n; ++i)   

11.  {   

12.     temp[i] = temp[i - 1] + temp[i - 2];   

13.  }   

14.  

15.  long result = temp[n];   

16.  

17.  delete[] temp;   

18.  

19.  return result;   

20.}  

 

10.活动安排问题

问题关键在于:

理解什么是相容性活动!

若区间[s1,f1)与区间[s2,f2)不相交,则称活动1与活动2是相容的,即s1>=f2或s2>=f1时,活动1与活动2相容。

(区间表示的是活动的起始时间s和结束时间f)

核心代码:

structaction

{

intbegin;

intend;

}a[1000];

intn;//n表示活动的总数

intsum=0;//sum表示能参加的活动的数量

voidsearch()

{

sum=1;

inttemp=a[0].end;//temp表示第一个活动结束的时间

for(inti=1;i

{

if(a[i].begin>=temp)

{

sum++;

temp=a[i].end;

}

}

}

voidselection_sort()

{

for(inti=0;i

{

intk=i;

for(intj=i+1;j

if(a[j].end

k=j;

structactiontemp=a[i];

a[i]=a[k];

a[k]=temp;

}

}

11.最优服务次序问题

思路是最短服务时间优先,先将服务时间排序,然后注意后面的等待服务时间既包括等待部分,也包括服务部分。

  贪心策略:

对服务时间最短的顾客先服务的贪心选择策略。

首先对需要服务时间最短的顾客进行服务,即做完第一次选择后,原问题T变成了需对n-1个顾客服务的新问题T'。

新问题和原问题相同,只是问题规模由n减小为n-1。

基于此种选择策略,对新问题T',选择n-1顾客中选择服务时间最短的先进行服务,如此进行下去,直至所有服务都完成为止。

每个客户需要的等待时间为:

T

(1)=t

(1);

T

(2)=t

(1)+t

(2);

......

T(n)=t

(1)+t

(2)+...+t(n);

总等待时间为:

T=n*t

(1)+(n-1)*t

(2)+(n-2)*t(3)+...+(n+1-i)*t(i)+...+2*t(n-1)+1*t(n)

注:

st[]是服务数组,st[j]为第j个队列上的某一个顾客的等待时间;su[]是求和数组,su[j]的值为第j个队列上所有顾客的等待时间;

第一种代码:

1.double greedy(vector<

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 政史地

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1