算法设计与分析试题Word文档下载推荐.docx
《算法设计与分析试题Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《算法设计与分析试题Word文档下载推荐.docx(9页珍藏版)》请在冰豆网上搜索。
1的规模即可解决问题。
符号三角形问题算法思想
第1行有n个符号。
两个同号下是“+”,两个异号下是“-”。
对于给定n,计算有多少个不同符号三角形,使其所含的“+”和“-”的个数相同。
◆回溯法是一种通用性解法,可以将回溯法看作是带优化的穷举法。
◆回溯法的基本思想是在一棵含有问题全部可能解的状态空间树上进行深度优先搜索,解为叶子结点。
搜索过程中,每到达一个结点时,则判断该结点为根的子树是否含有问题的解,如果可以确定该子树中不含有问题的解,则放弃对该子树的搜索,退回到上层父结点,继续下一步深度优先搜索过程。
◆在回溯法中,并不是先构造出整棵状态空间树,再进行搜索,而是在搜索过程,逐步构造出状态空间树,即边搜索,边构造。
减枝:
+(-)个数超过n*(n+1)/4;
n*(n+1)/2为奇数,
对于符号三角形问题,用n元组x[1:
n]表示符号三角形的第一行的n个符号。
当x[i]=1时,表示符号三角形的第一行的第i个符号为“+”号;
当x[i]=0时,表示符号三角形的第一行的第i个符号为“-”号;
1≤i≤n。
由于x[i]是二值的,所以在用回溯法解符号三角形问题时,可以用一棵完全二叉树来表示其解空间。
在符号三角形的第一行的前i个符号x[1:
i]确定后,就确定了一个由i*(i+1)/2个符号组成的符号三角形。
下一步确定了x[i+1]的值后,只要在前面已确定的符号三角形的右边加一条边,就可以扩展为x[1:
i+1]所相应的符号三角形。
最终由x[1:
n]所确定的符号三角形中包含的“+”号个数与“-”号个数同为n*(n+1)/4。
因此在回溯搜索过程中可用当前符号三角形所包含的“+”号个数与“-”号个数均不超过n*(n+1)/4作为可行性约束,用于剪去不满足约束的子树。
对于给定的n,当n*(n+1)/2为奇数时,显然不存在所包含的“+”号个数与“-”号个数相同的符号三角形。
用c[i][j]记录序列Xi和Yj的最长公共子序列的长度。
其中,Xi={x1,x2,…,xi};
Yj={y1,y2,…,yj}。
证明:
最长公共子序列问题的动态规划算法的递归结构为:
动态规划与分治法相同之处是也将原问题分解为若干子问题,再递归求解;
不同之处是所分解的子问题彼此并不独立,而是互有重叠。
a)最长公共子序列的结构
若用穷举搜索法,耗时太长,算法需要指数时间。
易证最长公共子序列问题也有最优子结构性质
设序列X=<
x1,x2,…,xm>
和Y=<
y1,y2,…,yn>
的一个最长公共子序列Z=<
z1,z2,…,zk>
,则:
i.若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
ii.若xm≠yn且zk≠xm,则Z是Xm-1和Y的最长公共子序列;
iii.若xm≠yn且zk≠yn,则Z是X和Yn-1的最长公共子序列。
其中Xm-1=<
x1,x2,…,xm-1>
,Yn-1=<
y1,y2,…,yn-1>
,Zk-1=<
z1,z2,…,zk-1>
。
最长公共子序列问题具有最优子结构性质。
b)子问题的递归结构
由最长公共子序列问题的最优子结构性质可知,要找出X=<
的最长公共子序列,可按以下方式递归地进行:
当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。
当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。
这两个公共子序列中较长者即为X和Y的一个最长公共子序列。
由此递归结构容易看到最长公共子序列问题具有子问题重叠性质。
例如,在计算X和Y的最长公共子序列时,可能要计算出X和Yn-1及Xm-1和Y的最长公共子序列。
而这两个子问题都包含一个公共子问题,即计算Xm-1和Yn-1的最长公共子序列。
我们来建立子问题的最优值的递归关系。
用c[i,j]记录序列Xi和Yj的最长公共子序列的长度。
其中Xi=<
x1,x2,…,xi>
,Yj=<
y1,y2,…,yj>
当i=0或j=0时,空序列是Xi和Yj的最长公共子序列,故c[i,j]=0。
建立递归关系如下:
c)计算最优值
由于在所考虑的子问题空间中,总共只有θ(m*n)个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。
计算最长公共子序列长度的动态规划算法LCS_LENGTH(X,Y)以序列X=<
作为输入。
输出两个数组c[0..m,0..n]和b[1..m,1..n]。
其中c[i,j]存储Xi与Yj的最长公共子序列的长度,b[i,j]记录指示c[i,j]的值是由哪一个子问题的解达到的,这在构造最长公共子序列时要用到。
最后,X和Y的最长公共子序列的长度记录于c[m,n]中。
1.最长公共子序列的结构
解最长公共子序列问题时最容易想到的算法是穷举搜索发,即对X的每一个子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中选出最长的公共子序列。
X的所有子序列都检查过后即可求出X和Y的最长公共子序列。
X的一个子序列响应与下标序列{1,2,……,m}的一个子序列,隐刺,X共有2m个不同子序列,从而穷举搜索发需要指数时间。
事实上,最长公共子序列问题也有最优子结构性质,有如下定理:
用反证法。
若zk≠xm,则<
z1,z2,…zk,xm>
是X和Y的长度为k+1的公共子序列。
这与Z是X和Y的一个最长公共子序列矛盾,因此,必有zk=xm=yn。
由此可知Zk-1是Xm-1和Yn-1的一个长度为k-1的公共子序列W,则将xm加在其尾部将产生X和Y的一个长度大于k的公共子序列。
此为矛盾,故Zk-1是Xm-1和Y的一个最长公共子序列。
由于zk≠xm,Z是Xm-1和Y的一个公共子序列。
若Xm-1和Y有一个长度大于k的公共子序列W,则W也是X和Y的一个长度大于k的公共子序列。
这与Z是X和Y的一个最长公共子序列矛盾,由此可知Z是Xm-1和Y的一个最长公共子序列。
函数A(n,m)定义如下:
设计计算函数值A(n,m)的递归函数。
阿克曼(Ackermann)函数的c++程序
#include<
iostream.h>
intackermann(intm,intn);
intmain()
{
intm,n,result;
cout<
<
"
Input:
endl;
cin>
>
m;
n;
result=ackermann(m,n);
result<
return0;
}
intackermann(intm,intn)
if(m==0)returnn+1;
if(n==0)returnackermann(m-1,1);
returnackermann(m-1,ackermann(m,n-1));
或者:
stdio.h>
intAck(intm,intn)
if(m==0)
returnn+1;
else
{
if(m!
=0&
&
n==0)
returnAck(m-1,1);
elseif(m!
n!
=0)
returnAck(m-1,Ack(m,n-1));
}
voidmain()
inta,b;
scanf("
%d%d"
&
a,&
b);
printf("
%d\n"
Ack(a,b));
在一个n×
n的棋盘上放置彼此不受攻击n个皇后。
即任何2个皇后不放在同一行或同一列或同一斜线上。
使用回溯法求解如下:
staticintn;
//皇后个数
staticint[]x;
//当前解
staticlongsum;
//当前已找到的可行方案数
publicstaticlongnQueen(intnn){
n=nn;
sum=0;
x=newint[n+1];
for(inti=0;
i<
=n;
i++)x[i]=0;
//初始户
backtrack
(1);
returnsum;
}
请设计方法(函数)backtrack(intt)。
【书上第五章,5.5节165页】
已知方法randomizedPartition(a,p,r)【书上第二章,2.9节39页】
(1)设计找出这n个元素中第k小的元素的算法。
(2)分析算法的时间复杂性。
template<
classType>
TypeRandomizedSelect(Typea[],intp,intr,intk)
if(p==r)returna[p];
inti=RandomizedPartition(a,p,r),
j=i-p+1;
if(k<
=j)returnRandomizedSelect(a,p,i,k);
elsereturnRandomizedSelect(a,i+1,r,k-j);
在最坏情况下,算法randomizedSelect需要O(n
)计算时间
但可以证明,算法randomizedSelect可以在O(n)平均时间内找出n个输入元素中的第k小元素。
设有n个活动的集合E={1,2,…,n},每个活动i(i∈E)都有一个要求使用公共资源的起始时间si和一个结束时间fi,且si<
fi。
【书上第四章,4.1节107页。
】
(1)写出在此活动集合E中选出最大的相容活动子集合的算法思想。
每个活动i都有一个要求使用公共资源的起始时间si和一个结束时间fi,且si<
如果选择了活动i,则它在半开时间区间[si,fi)内占用资源。
若区间[si,fi)与区间[sj,fj)不想交,则称活动i与活动j是相容的。
也就是说,当si>
=fi或sj>
=fj时,活动i与活动j是相容的。
活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。
(2)根据
(1)的算法思想设计算法。
voidgreedyselector(intn,types[1,typef[],boola[]]
{
a[1]=true;
intj=1;
for(inti=2;
=n;
i++){
if(s[i]>
=f[j]){
a[i]=true;
j=i;
elsea[i]=false;
(3)分析算法的时间复杂性。
O(nlogn)θ(0)