算法设计技巧与分析习题参考答案Word格式.docx
《算法设计技巧与分析习题参考答案Word格式.docx》由会员分享,可在线阅读,更多相关《算法设计技巧与分析习题参考答案Word格式.docx(13页珍藏版)》请在冰豆网上搜索。
数组的所有元素之和∑A[i]{i=1…n}
SUM(low,high)
1.ifhigh=lowthen
2.returnA[low]
3.else
4.mid←(low+high)/2
5.s1←SUM(low,mid)
6.s2←SUM(mid+1,high)
7.returns1+s2
8.endif
工作空间:
mid~(logn),s1&
s2~
(1)(后序遍历树,不断释放空间,故为常数
(1)),总的工作空间为(logn).
6.6用分治法求元素x在数组A中出现的频次。
freq(A[low,high],x)
1.ifhigh=lowthen
2.ifA[low]=xthen
3.return1
4.else
5.return0
6.endif
7.else
8.mid←(low+high)/2
9.f1←freq(A[low,mid])
10.f2←freq(A[mid+1,high])
11.returnf1+f2
12.endif
复杂度:
T(n)=T(n/2)+T(n/2)≈2T(n/2)(设2k≤n<
2k+1)
=…=2kT(n/2k)=2kT
(1)=n
6.16修改后的MERGESORT算法
最大比较次数
最小比较次数
令n/2k=m≥2,展开可知:
T(n)=2kT(n/2k)+kn-(2k-1)
=n/m×
m(m-1)/2+nlog(n/m)-n/m+1
=n(m-1)/2+nlog(n/m)-n/m+1
若T(n)=(nlogn),其中表达式有nm,nlogn,nlogm,n/m等.
有n/m<
nlogm<
nm且须有nm=O(nlogn),i.e.,nm≤c·
nlogn,
则须有m≤c·
logn.可令c=1,则m≤logn.另一方面,
C(n)=2kC(n/2k)+kn/2=n/m×
(m-1)+(n/2)log(n/m)=(nlogn)
6.35
split(A[low,...high])
1.x←A[low]//备份为x
2.while(low<
high){
3.while(low<
high&
&
A[high]>
0)--high;
4.A[low]←A[high]
5.while(low<
A[low]≤0)++low;
6.A[high]←A[low]
7.}
8.A[low]←x//这时,low=high
7.3动态规划法计算二项式系数
,并分析其时间复杂度。
1.fori←1ton
2.C[i,0]←1;
C[i,i]←1
3.endfor
4.fori←2ton
5.forj←1toi-1/min(k,i-1)//例如计算C[6,2]
6.C[i,j]←C[i-1,j-1]+C[i-1,j]
7.end
8.endfor
9.returnC[n.k]
复杂度分析:
或
8.5硬币的面值为1,2,4,8,...,2k,要兑换的值n<
2k+1,用贪心算法解这个问题,要求算法复杂度为O(logn)
k+1个不同硬币的面值,其中包括单位币(面值为1)
若要兑换的值n,给出各个面值硬币的数目num[0…k]
1.将k+1个不同的面值按递增顺序排列,记为Value[0...k]
2.num[0…k]←0
3.forj←kdownto0
4.num[j]←n/Value[j]
5.n←n-num[j]×
Value[j]
6.endfor
7.returnnum[0…k]
8.16修改Dijkstra算法,使它找出最短路径和它的长度。
1.X={1};
Y←V-{1};
λ[1]←0;
pre[1]←0;
2.fory←2ton
3.ify相邻于1thenλ[y]←length[1,y]
4.elseλ[y]←∞
5.endif
6.endfor
7.forj←1ton-1
8.令y∈Y,使得λ[y]为最小的
9.X←X∪{y}
10.Y←Y-{y}
11.for每条边(y,w)
12.ifw∈Yandλ[y]+length[y,w]<
λ[w]then
13.λ[w]←λ[y]+length[y,w]
14.pre[w]←y
14.endif
15.endfor
16.endfor
输出最短路径
voidPrintPath(intnode)//输出格式为1→…→node
{if(node==1)print(“1”);
else{
PrintPath(pre[node]);
//先递归再输出
print(“→”,node);
}
}
13.2考虑3着色问题,给出一个算法判断一张图G=(V,E)的3着色向量c[1…n]是否是合法的。
图G=(V,E),向量c[1…n]
flag=true若合法着色;
否则flag=false
2.fori←1ton
3.ifc[i]≠0
4.for(i,j)∈E
5.ifc[j]≠0andc[j]=c[i]
6.returnfalse;
7.endif
9.endif
10.endfor
11.returntrue
13.3考虑3着色问题,给出一个算法判断一张图G=(V,E)的3着色向量c[1…k]是否是部分的。
图G=(V,E),向量c[1…k]
true若着色是部分的;
否则输出false
2.fori←1tok
5.ifj≤kandc[j]≠0andc[j]=c[i]
13.10设计一个回溯算法来生成数字1,2,…,n的所有排列。
数字1,2,…,n
数字1,2,…,n的所有排列c[1,…,n]向量
1.fork←1ton
2.c[k]←0
5.k←1
6.whilek≥1
7.whilec[k]≤n-1
8.c[k]←c[k]+1
9.ifc为合法的thenoutputc(andgoto12)
10.elseifc为部分解thenk←k+1
11.endwhile
12.c[k]←0
13.k←k-1
14.endwhile
14.7对二分查找算法进行随机化,即每次迭代时,随机选择剩下的位置代替搜索空间减半,假设在low与high之间每个位置被选中的概率都是相同的。
比较这种随机化算法与二分查找的表现。
n个元素的升序数组A[1…n]和元素x
若x=A[j],1jn,则输出j,否则输出0
1.low←1;
high←n;
j←0
2.while(lowhigh)and(j=0)
3.mid←(low+high)/2/mid←random(low,high)
4.ifx=A[mid]thenj←mid
5.elseifx<
A[mid]thenhigh←mid-1
6.elselow←mid+1
7.endwhile
8.returnj
时间复杂度分析
将每次迭代时随机选择的位置记为k,且在low与high之间每个位置被选中的概率都是1/n,期望比较次数C(n)满足
nC(n)=n+2{C
(1)+C
(2)+…+C(n-2)+C(n-1)}
(1)
(n-1)C(n-1)=n-1+2{C
(1)+C
(2)+…+C(n-2)}
(2)
(2)-
(1)nC(n)-(n-1)C(n)=1+2C(n-1)
nC(n)=1+(n+1)C(n-1)
nC(n)=1+(n+1)C(n-1)
(可将C(n)=n代入推导过程,以验证其正确性)因此,随机化拟二分查找的时间复杂度为O(n),二分查找的时间复杂度为O(logn)。
随机化方法的效率反而比二分查找低,其原因在于…
14.10设L=x1,x2,…,xn是一个元素序列,其中元素x恰好出现k次(1≤k≤n),我们要找到一个j,使得xj=x。
考虑重复执行下面的过程直到找到x为止。
生成一个1到n之间色随机数i,并检查是否xi=x。
在平均情况下,这种方法和线性方法查找哪一种方法快?
请说明。
解:
(1)随机查找的情况
不妨设第i1,i2,…,ik个元素等于x,记I={i1,i2,…,ik},|I|=k,则P{i∈I}=k/n,记p=k/n,q=1-p,则查找长度的数学期望
E(ASL)=p×
1+q×
p×
2+…+qi-1×
i+…=1/p=n/k
(2)线性查找的情况
其中,分母=n(n-1)(n-2)…(n-i+1)=n!
/(n-i)!
分子=(n-k)(n-k-1)…(n-k-i+2)×
k×
i=(n-k)!
×
i/(n-k-i+1)!
则通项可写为
于是,
可以证明上式的成立。
事实上,上式等价于
即要证明
成立。
思路:
右边变换→左边形式
,另一方面
,(*)其中
将以上各式(除了*式)相加,即可得到
即有
总结:
随机查找
,线性查找
,
因为
,故线性查找更快。
14.16修改14.7节的随机抽样算法,使得它不再需要布尔数组S[1…n],假设n比m大得多,比如n>
m2.
算法设计如下:
1.k←1
2.whilek≤m
3.r←random(1,n)
4.i←k-1
5.whilei≥1andr≠A[i]
6.i←i-1
7.endwhile
8.ifi=0
9.A[k]←r
10.k←k+1
11.endif
12.endwhile
复杂度分析如下:
每次随机生成一个新元素r,要查找r是否已经出现在已经选定的数字中。
设生成第i个有效随机数时,平均要产生E(Xi)次,则复杂度
容易证明,
且有
因为m2<
n,则
,于是
14.16另解:
算法设计思路如下:
生成一个[1,n]之间的随机数r,互换X[n]和X[r];
再生成一个[1,n-1]之间的随机数r,互换X[n-1]和X[r];
…
再生成一个[1,n-m+1]之间的随机数r,互换X[n-m+1]和X[r];
返回X[n-m+1…n],即为随机选择的m个数。
好处:
不需要重复产生随机数;
不需要额外空间。
1.fori←ndownton-m+1
2.r←random(1,i)
3.X[r]←→X[i]
4.endfor
5.returnX[n-m+1…n]
时间复杂度:
(m).空间复杂度:
(1).