算法(复习题)1

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

平均情况:设待查找的元素在数组中的概率为P,不在数组中的概率为1-P,若出现在数组中每个位置的概率是均等的为p/n
T(n)=P1D1+P2D2+...+PiDi+(1-P)Dn+1
=p/2+n(1-p/2)
1.叙述分治算法和动态规划算法的基本思想,并比较两种算法的异同。

答:分治法将待求解的问题划分成K个较小规模的子问题,对这K个子问题分别求解,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解. 动态规划将待求解的问题分解成若干的子问题,自底向上地通过求解子问题的解得到原问题的解。

动态规划将每个子问题只求解一次并将其解保存在一个表格中,当需要再次求解此子问题时,只是简单的通过查表过的该子问题的解,避免了大量的重复计算.
异同:分治法求解的问题分解后的子问题都是独立的,而使用动态规划求解的问题分解后得到的子问题往往不是相互独立的。

分治法是自顶向下用递归的方法解决问题,而动态规划则是自底向上非递归解决问题。

1.简述分治算法求解过程的三个阶段。

答:(1)划分:既然是分治,当然需要把规模为n的原问题划分为k个规模较小的子问题,并尽量使这k个子问题的规模大致相同。

(2)求解子问题:各子问题的解法与原问题的解法通常是相同的,可以用递归的方法求解各个子问题,有时递归处理也可以用循环来实现。

(3)合并:把各个子问题的解合并起来,合并的代价因情况不同有很大差异,分治算法的有效性很大程度上依赖于合并的实现。

2.叙述分治法的基本思想,并分析分治法与减治法二者的区别。

答:分治法将待求解的问题划分成K个较小规模的子问题,对这K个子问题分别求解,再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解.
区别:分治法是把一个大问题划分成若干个子问题,分别求解各个子问题,然后把子问题的解进行合并并得到原问题的解。

减治法同样是把一个大问题划分成若干个子问题,但是这些子问题不需要分别求解,只需求解其中的一个子问题,因而也无需对子问题的解进行合并。

3.设计分治算法求一个数组中最大元素的位置,建立该算法时间复杂性的
递推式并给出其复杂性的大O表示。

答:设数组a1,a2...an
int maxpos(a[],i,j);
{if(i==j) return i;
mid=(i+j)/2;
lmaxpos=maxpos(a,i,mid);
rmaxpos=maxpos(a,mid+1,j);
if(a[lmaxpos]>=a[rmoxpos])
return lmaxpos;
else
return rmaxpos;}
T(1)=O(n) n=1;
T(n)=2T(n/2)+O(1) n>1;
求得复杂性为O(n)
4.阅读下面一段折半查找算法,回答问题。

int BinarySearch(int a[],int x,int n)
{
int left=0,right=n-1;
while(left<=right){
int middle=(left+right)/2;
if(x==a[middle]) return middle;
if(x>a[middle]) left=middle+1;
else right=middle-1;
}
return -1;
}
(1)给出该算法的复杂性递归方程,用展开法求解,并给出其渐进复杂性的大O表示。

T(1)=1 n=1 T(n)=T(n/2)+1 (n>=2) O(logn)
(2)修改折半查找算法使之能够进行范围查找。

所谓范围查找是要找出在给定值a和b之间的所有元素(a≤b)。

int BinarySearch(int s[],int r,int l,a,b)
{
mid=(l+r)/2;
if(s[mid]>b) BinarySearch(s,mid-1,l,a.b);
else (s[mid]<a) BinarySearch(s,r,mid+1,a,b);
else{输s[mid];
BinarySearch(s,mid-1,l,a,s[mid]);
BinarySearch (s,r,mid+1,s[mid],b);
}
5.什么是最优化问题?
答:最优化问题有n个输入,它的解由这n个输入的一个子集组成,这个
子集必须满足某些事先给定的条件,这些条件称为约束条件,满足约束
条件的解称为可行解。

满足约束条件的可行解可能不只一个,为了衡量
这些可行解的优劣,事先给出一定的标准,这些标准通常以函数的形式
给出,这些标准函数称为目标函数。

使目标函数取得极值(极大或极小)
的可行解称为最优解这类问题就称为最优化问题。

6.最大子段和问题:给定由n个整数组成的序列(a1, a2, …, an),最大子段
和问题要求该序列形如ai+…+aj的最大值(1≤i≤j≤n),当序列中所有整
数均为负整数时,其最大子段和为0。

分别用蛮力法、分治法和动态规
划法设计求解最大子段和问题的算法的伪代码描述,并分析每种方法的
渐进复杂性。

(1)蛮力法
int maxsum (int n,int a[],int besti,int bestj){
int sum=0;
for(int i;i<=n;i++){
int thissum=0;
for(int j=i;j<=n;j++){
thissum +=a[j];
if(thissum>sum){
sum=thissum;
besti=i;
bestj=j;}}
}return sum;
}
基本操作为:第二个for循环中的条件语句,故复杂性为:O(n^2)。

(2)分治法
将a1,a2,……,an划分为两个长度相等的子序列a1,a2…..,an/2和an/2+1,an/2+2,……,an○1原序列最大子段和为前一个子序列的最大子段和。

○2原序列最大子段和为后一个子序列的最大子段和。

○3原序列的最大子段和=ai+….+aj 1<=i<=n/2 n/2+1<=j<=n ○1○2递归求解,○3s1=Max(ai+….+ak) (1<=i<=n/2) s2=Max(ak+…+aj)(n/2+1<=j<=n) 比较丧钟情况下的结果,取较大的为原问题的解。

复杂性方程为:T(1)=1 n=1,T(n)=2T(n/2)+n n>1;解得时间复杂度:O(nlogn)(3)动态规划法
int maxsum (int n,int a[]){
int sum=0,b=0;
for(int i=1;i<=n;i++){
if(b>0) b+=a[i];
else b=a[i];
if(b>sum) sum=b;}
return sum;}
递归方程 b(j)=b(j-1)+aj b(j-1)>0 b(j)=aj b(j-1)<=0
时间复杂度为:O(n)
7.给出贪心法的一般过程描述。

开始时解集S为空,然后使用选择函数按照某种贪心策略从候选集合C中
选择一个元素X,用可行函数去判断解集合S加入X后是否可行,把X合并
到解集合S中,并把他从候选集合C中删除,否则,丢弃X,从候选集合C
中根据贪心策略在选择一个元素,重复上述过程,只到找到一个满足解
决函数的完整解。

8.简述贪心法求解问题的两个特征,并说明贪心法和动态规划法的区别。

答:最优子结构性质:当一个问题的最优解包含其子问题的最优解时,
称此问题具有最优子结构性质,也称此问题满足最优性原理。

贪心选
择性质:所谓贪心选择性质是指问题的整体最优解可以通过一系列局
部最优的选择,即贪心选择来得到。

区别:动态规划算法是把一个复杂问题分解为若干个相互重叠的子问
题,通过求解子问题形成一系列决策得到原问题的解;而贪心法是把
一个复杂问题分解为一系列较为简单的局部最优选择,每一步选择都
是对当前的一个扩展,直到获得问题的完整解。

9.假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。

设计一个有效的贪心算法进行会场安排。

10.分析回溯法的基本思想。

答:回溯法从根结点出发,按照深度优先策略遍历解空间树,搜索满足约束条件的解。

在搜索至树中任一结点时,先判断该结点对应的部分解是否满足约束条件,或者是否超出目标函数的界,也就是判断该结点是否包含问题的(最优)解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即所谓剪枝;否则,进入以该结点为根的子树,继续按照深度优先策略搜索。

11.什么是深度优先的问题状态生成法?什么是宽度优先的问题状态生成法?答:深度优先的问题状态生成法:如果对一个扩展结点R,一旦产生了它的一个儿子C,就把C当做新的扩展结点。

在完成对子树C(以C为根的子树)的穷尽搜索之后,将R重新变成扩展结点,继续生成R的下一个儿子(如果存在)。

宽度优先的问题状态生成法:在一个扩展结点变成死结点之前,它一直是扩展结点。

12.用递归形式和回溯形式对回溯法进行伪代码描述,要求对算法中的变量、函
数等有适当的注释。

答:递归形式
主算法
1. X={ };
2. flag=false;
3. advance(1);
4. if (flag) 输出解X;
else输出“无解”;
advance(int k)
1. 对每一个x∈Sk 循环执行下列操作
1.1 xk =x;
1.2 将xk 加入X;
1.3 if (X是最终解) flag=true; return;
1.4 else if (X是部分解) advance(k+1);
迭代形式:
1.X={ };
2.flag=false;
3.k=1;
4.while (k>=1)
4.1 当(Sk 没有被穷举)循环执行下列操作
4.1.1 xk =Sk 中的下一个元素;
4.1.2 将xk 加入X;
4.1.3 if (X为最终解) flag=true; 转步骤5;
4.1.4 else if (X为部分解) k=k+1; 转步骤4;
4.2 k=k-1; //回溯
5.if flag 输出解X;
else 输出“无解”;
13.设计用回溯法求解0/1背包问题的剪枝函数,并给出相应算法的伪代码描述。

X=(x1,x2,….,xn) xi={0,1}
x1w1+x2w2+…+xiwi<=c
左子树:cw+w[i]>c 右子树:cp+lefts(i+1)<=bestP
将个物品按单位重量价值从大到小排序
bestp=0;BackTrack(1);输出背包的最大价值bestP;
BackTrack( int i)
{
if(i>n)
{
if(bestP<cp) bestP=cp;return;
}
}
若(cw+w[i]<=c)则
cw=cw+w[i];
cp=cp+p[i];BackTrack(i+1);
若(cp+lefts(i+1)>bestP)则
cw=cw-w[i];cp=cp-p[i];
14.给定一个正整数集合X={x1,x2,…,x n}和一个正整数y,设计回溯算法,求集
合X的一个子集Y,使得Y中元素之和等于y。

若X={1,2,3,5,7},y=8,用设计的回溯算法求解该问题的所有解。

答:解形式:Y={y1.y2,……yn} y
i
={0.1}
约束条件: n
∑=y
i x
i =y
i=1
左子树:sum+x
i
>y 右子树:sum=lefts(i+1)<y
Void Backtrack(int i){
if(i<n)
if(sum==y){
输出 Y; return;}
y[i]=1;sum+=x[i]; //进入左子树
if(sum<=y)
Backtrack(i+1);
y[i]=0;sum-=x[i]; //进入右子树
if(sum+lefts(i+1)>=y)
Backtrack(i+1);
}
解是:(1,1,0,1,0)
15.n皇后问题:在n×n的棋盘上摆放n个皇后,使任意两个皇后都不能处于同一
行、同一列或同一斜线上。

(1)给出n皇后问题的解向量形式及解释。

X=(x1,x2,…,xn) 1<=i<=n
每一行可以而且必须摆放一个皇后,所以N皇后问题可以用X=(x1,x2,…,xn) 表示1<=i<=n并且1<=xi<=n,即第i个皇后放在第i行第xi列上。

(2)分析并表示n皇后问题可行解的约束条件。

两个皇后不能位于同一行同一列上,xi不等于xj
两个皇后不能位于同一斜线上,|i-xi|不等于|j-xj|
(3)根据(1)和(2)中给出的解向量和约束条件设计求解n皇后问题的回溯算法。

Void Queue(int n)
{if(t>n) 输出数组X;
else{for(i=1;i<=n;i++)
{x[t]=i;if(place(t))
Queue(t+1);}}}
Bool place(int k)
{
For(i=1;i<=n;i++)
If(x[k]==x[i]||abs(k-x[k])==abs(i=x[i]))return false;
Else return true;
}
16.图着色问题:给定无向连通图G=(V, E)和正整数m,如果这个图不是m可着色
的就给出否定回答;如果这个图是m可着色的,则找出至少一种着色法。

(1)给出图着色问题的解形式,描述其解空间。

C=(c1,c2,……,cn) Ci属于{1,2,…,m}(1<=i<=n)
用m种颜色为无向图着色,其中V的顶点个数为N,可用一个n元
组C=(c1,c2,……,cn)来描述图的一种可能的着色,其中 Ci属于
{1,2,…,m}(1<=i<=n),表示赋予顶点i的颜色。

(2)用回溯法设计图着色问题的伪代码,说明其最坏情况下的复杂性。

1.将数组color[n]初始化为0;
2.k=1;
3.while(k>=1)
3.1依次考察每一种颜色,若顶点K的着色与其他顶点的着色不
发生冲突,则转到3.2
3.2若顶点已全部着色,则输出数组color[n],返回;
3.3否则 3.3.1若顶点k是一个合法着色,则k=k+1,转3处理
下一个顶点;
3.3.2否则,重置顶点k的着色情况,k=k-1,转3回溯;
17.比较回溯法和分支限界法的相同点和不同点。

答:(1)求解目标不同:一般情况下,回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。

(2)搜索方式的不同:回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。

18.在一个序列中出现次数最多的元素称为众数。

请设计分治算法寻找众数。

答:设数组a,公有变量Largest和element(Largest表示出现最多的元素的出现次数,element 表示出现次数最多的元素)
void Mode(int L,int r){
int [] Lr=new int[2];
int med=select(a,L,r,((r-L+1)/2));
split(a,med,L,r,Lr);/*用中位数把数组a [l:r] 划分成a[L:Lr[0]-1],a[Lr[0]:Lr[1]],a[Lr[1]+1:r]*/
if(Largest<Lr[1]-Lr[0]+1){
Largest=Lr[1]-Lr[0]+1;
Element=med;
}
if(Largest<Lr[0]-L) //Lr[0]-1+L+1
Mode(L,Lr[0]-1);
if(Largest<r-Lr[1])
Mode(Lr[1]+1,r);
}
19.活动安排问题:
设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。

每个活动i都有一个要求使用该资源的起始时间s i和一个结束时间f i,且s i <f i。

如果选择了活动i,则它在半开时间区间[s i, f i)内占用资源。

若区间[s i, f i)与区间[s j, f j)不相交,则称活动i与活动j是相容的。

也就是说,当s i ≥f j或s j≥f i时,活动i与活动j相容。

要求在所给的活动集合中选出最大的相容活动子集合。

(1)给出活动安排问题的形式化描述(包括解形式,约束条件,目标函
数)。

N元向量X=(x1,x2,….,xn)xi属于{1,0} 1<=i<=n
对于任意活动i,j,若xi=xj=1,则[si,fi]与上[sj,fj]不等于空
X中1的个数最多
(2)设计求解活动安排问题的至少3种贪心准则,并对不能保证得到最
优解的策略举出反例。

1.选择具有最早开始时间的相容活动反例:开始早结束晚
2.选择具有最短时段的相容活动
3.选择具有最早完成时间的相容活动
(3)利用下面的算法框架选择正确的贪心准则设计求解活动安排问题的
伪代码描述(C/C++描述)。

void GreedySelector(int n,Type s[],Type f[],bool A[])
{ }
//数组s和f分别存储n个活动的开始时间和结束时间
//数组A中存储问题的解
void GreedySelector(int n,type s[],type f[],bool a[])
{ a[1]=1;j=1;count=1;
for(i=2;i<=n;i++)
{if(s[i]>f[i])
{a[i]=1;j=I;count++;}
else a[i]=0;}
return count;}
20.活动安排
int Active(int s[],int f[],int n)
{将所有活动的开始时间和结束时间按发生的先后顺序,结束时间排在开始时间之前,并存放于x[];
for(i=1;i<=n;i++)
{if(x[i]是某个活动的开始时间)m++;
else
{if(m>sum)
sum=m;
m--;}
}
return sum;
}。

相关文档
最新文档