大连理工大学算法与设计算法讲解.docx
- 文档编号:5635974
- 上传时间:2022-12-29
- 格式:DOCX
- 页数:30
- 大小:962.76KB
大连理工大学算法与设计算法讲解.docx
《大连理工大学算法与设计算法讲解.docx》由会员分享,可在线阅读,更多相关《大连理工大学算法与设计算法讲解.docx(30页珍藏版)》请在冰豆网上搜索。
大连理工大学算法与设计算法讲解
1.写出Prim算法描述,并给出时间复杂度的分析。
算法描述:
假设N=(V,E),TE是N最小生成树边的集合。
算法从U={u0}(u0∈V),TE={}开始,重复执行下述操作:
在所有u∈V,v∈V-U的边(u,v)∈E中,找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直到U=V为止。
此时TE中必有n-1条边,则T=(V,TE)为最小生成树
时间复杂度:
算有2个内循环,其一是选择具有最小代价的边,频度为n-1;其二是重新选择最小代价的边,频度为n,因此prim算法的时间复杂度为O(n2).与图中的边数无关,因此适合于求边稠密的图的最小生成树。
2.给出Prim算法的正确性证明。
正确性证明:
设由算法生成的MST为T1,假设存在T2,为与T1具有相同边数最多的实际MST,则w(T1)>=w(T2)。
假定e2=xy为在T2中且不在T1中的且具有最小权值的边。
记在T1中,从根结点A到x的路径为Px1x2…xs(x1=A,xs=x),从A到的y路径为Py1y2…yt(y1=A,yt=y)。
不妨假定在算法执行过程A先到达x,再到达y。
因为y是通过yt-1yt进入的T1,所以w(yt-1yt)<=w(xy),否则xy先进入T1。
设在路径Px1x2…xs和Py1y2…yt上且不在T2中权值最小的边e1,将e1加入T2中构成回路。
在回路中找一条在T2中但不在T1中的边e3删除之,得T2’
若:
(1)w(e1) (2)w(e1)=w(e3),T2’与T1具有相同边数比T2与T1具有相同边数多1,与T2是与T1具有相同边数最多的假定矛盾; (3)w(e1)>w(e3),因为w(e1)<=w(yt-1yt)<=w(xy),所以w(e3) 所以,Prim算法执行过程是正确的. Prim算法正确性证明 数学归纳法: 当n=1时,显然成立。 假设n=k时,用prim算法构建的是最小生成树。 当n=k+1时,设最后加入最小生成树的点是v。 在这个n+1个结点的树中任意添加一条边。 分两种情况。 1.添加的这条边中任意一个顶点都不是v。 相当于在去掉了结点v的又k个结点的生成树中添加一条边,根据MST性质,这条边一定是产生回路中权值最大的边。 再添加上顶点v,依旧是之前的回路,所以添加的边依旧是现在回路中最长的边。 所以当n=k+1时成立 2..现在只需要证明,当添加的边其中有一个顶点是v的情形成立即可。 假设其余k个结点为uk(k=1,2,3….)其中W(U1v)最小。 任意连接Uk(k=2,3…..),一定会出现一条回路。 因为采用的是Prim算法,切V结点是最后一个加入进来的,因此回路中不存在大于W(U1V)或者大于W(UkV)的边,并且W(UkV)>W(U1V),所以加入的UkV是回路中权值最大的边,符合MST性质,因此,这种情形下,n=k+1成立 综上所述,prim算法正确。 3..写出一个怎样找到一个图中的割点的算法描述。 由于上述算法是一个遍历的过程,因此求关键点的事假复杂度为O(n+e). 4.n个节点的二叉树有多少棵? 给出证明。 可以分析,当n=1时,只有1个根节点,则只能组成1种形态的二叉树,令n个节点可组成的二叉树数量表示为h(n),则h (1)=1;h(0)=1; 当n=2时,1个根节点固定,还有2-1个节点。 这一个节点可以分成(1,0),(0,1)两组。 即左边放1个,右边放0个;或者左边放0个,右边放1个。 即: h (2)=h(0)*h (1)+h (1)*h(0)=2,则能组成2种形态的二叉树。 当n=3时,1个根节点固定,还有2个节点。 这2个节点可以分成(2,0),(1,1),(0,2)3组。 即h(3)=h(0)*h (2)+h (1)*h (1)+h (2)*h(0)=5,则能组成5种形态的二叉树。 以此类推,当n>=2时,可组成的二叉树数量为h(n)=h(0)*h(n-1)+h (1)*h(n-2)+...+h(n-1)*h(0)种,即符合Catalan数的定义,可直接利用通项公式得出结果。 令h (1)=1,h(0)=1,catalan数(卡特兰数)满足递归式: h(n)=h(0)*h(n-1)+h (1)*h(n-2)+...+h(n-1)h(0)(其中n>=2) 该递推关系的解为: h(n)=C(2n,n)/(n+1)(n=1,2,3,...) 5.给出利用DFS进行拓扑排序算法描述,并给出时间复杂度分析 把图中节点的状态分成三种。 white代表节点还未被搜索到,gray代表节点已被搜索到但还未被处理完,black代表节点已被处理完。 数组topo[]来记录每个顶点的编号。 把图中所有的节点的状态初始化为white,topoNum=n,从顶点号为1的顶点开始搜索color[1]=gray. 设当前搜索到的节点为v,则按深度优先的方式搜索它的邻接点,若存在某个邻接点状态为white,则把该邻接点的状态改为gray,把它作为当前搜索到的节点,继续按深度优先方式搜索;若所有的邻接点状态都不是white则把当前节点状态改为black,topo[v]=topoNum,topoNum--,然后退回到上一个节点。 当所有节点的状态都为black时,退出循环。 时间复杂度: 设顶点数为n,边数为m。 算法分为两部分: 初始化和搜索节点,显然初始化的时间复杂度是O(n),搜索节点则是按按深度优先的方式查找所有的边,时间复杂度为O(m+n),故此时间复杂度为O(m+n)。 6.对于给定的长度为n的数字序列,给出一个算法,找到该序列中的最长不降子序列(要求至少找到一个)。 即对于序列a1,a2,a3,……,an,找到一组1<=j1 并分析时间复杂度 解答: 定义两个数组maxLength[n]和preEle[n] maxLength[i]表示: 序列a1,a2,a3,……,ai中,ai之前(包括ai)最长的子序列的长度 preEle[i]表示: 上诉子序列中ai的前一个元素的编号。 初始: maxLength[1]=1,preEle数组全部置0 for(intk=2;k<=n;k++) {//对于a1,a2,a3,……,ak-1中小于ak的所有at所对应的maxLength[t]中找到最大的一个,将该maxLength[t]加上1即为maxLength[k],找到的t即为at在当前最长不下降子序列中的前一个元素 maxLength[k]=max{maxLength[t]|1<=t preEle[k]=上式中找到的t; } 最后,maxLength[n]数组中最大的数即为所求的最长不下降子序列的长度,对应的元素即为最长不下降子序列的最后一个元素,从此元素开始,顺着该元素对应的preEle数组元素向前找对应的元素,直到找到的元素对应的preEle数组元素为0,便得到所求序列。 时间复杂度分析: 为了获得每个元素ai对应的数组元素maxLength[i]的取值,都需要对原序列中ai之前的每个数进行检验,故时间复杂度为O(n2)。 举例: 数字序列: 192385106 找到的maxLength数组中最大的元素为maxLength[7]和maxLength[8],所以找到两个所求的序列,分别为: 1,2,3,5,6 1,2,3,5,10 7.已知一有向图G=(V,E),其每条边(u,v)∈E均对应有一个实数值r(u,v),表示从顶点u到顶点v之间的通信线路的可靠性,取值范围为0≤r(u,v)≤1,定义r(u,v)为从u到v的线路不中断的概率,并假定这些概率是相互独立的。 写出一个有效算法,来找出两个指定顶点间的最可靠的线路。 解答: 运用Dijkstra算法的思想,将原来的加法计算改为乘法即可。 例如下图: 解答过程如下: 每一行的意义: 从A出发,经过所用可能路径, 到达各点的最可靠效率 第一次找到B之后,就不用再找了, 因为再乘以任何r(u,v)([0-1]) 会使得A到B的可靠性减小 8.Floyd算法求出任意两点间的最短距离。 例: 有向图中有四个点,点之间的距离如下所示: 解答: for(k=0;k for(i=0;i for(j=0;j A[i,j]=min{A[i,j],A[i,k]+A[k,j]} 算法思想: 从图的带权邻接矩阵A=[a(i,j)]n×n开始, 递归地进行n次更新,即由矩阵D(0)=A, 按一个公式,构造出矩阵D (1); 又用同样地公式由D (1)构造出D (2); 最后又用同样的公式由D(n-1)构造出矩阵D(n)。 矩阵D(n)的i行j列元素便是i号顶点到j号顶点的最短路径长度 9.对于矩阵乘法: 第1个乘号第(n-1)个乘号 A1×A2×…×An d0×d1d1×d2dn-1×dn 给出每个乘法运算的执行顺序,使得进行整个矩阵乘法运算过程中进行的数值乘法次数最少。 解答: 定义函数cost(low,high),表示计算矩阵A(low)×…×A(high)所需的最少数值乘法次数,root(low,high)表示相应于上述cost(low,high)的进行的最后一次乘法的位置。 则状态转移方程为: 当low==high时,cost(low,high)=0,root(low,high)=-1 当low cost(low,high)=min{cost(low,k)+cost(k+1,high)+d(low-1)×dk×d(high)|low<=k<=high-1}式 (1) root(low,high)=k(式 (1)中的k) 伪代码实现: 定义两个二维数组cost[1...n][1…n]和root[1…n][1…n] //初始化数组的对角线元素 for(i=1;i<=n;i++) cost[i][i]=0; root[i][i]=-1; //按一定的顺序填充数组 for(low=n-1;low>=1;low--) for(high=low+1;high<=n;high++) cost[low][high]=maxNum;//maxNum表示无穷大 for(k=low;k if(cost[low][k]+cost[k+1][high]+dlow-1×dk×dhigh cost[low][high]=cost[low][k]+cost[k][high]+dlow-1×dk×dhigh; root[low][hith]=k; 最终,cost[1][n]即为进行该矩阵乘法所需的最少代价。 对root数组进行如下的后序遍历,即可得到代价最少的乘法次序,乘法进行的次序存储在数组multOrder[]中 intmultOrderNext; extractOrderWrap(intn,introot[],multOrder[]) { multOrderNext=1; extractOrder(1,n,multOrder); } extractOrder(intlow,inthigh,introot[],intmultOrder[]) { Intk; If(low k=root[low][high]; extractOrder(low,k,multOrder); extractOrder(k+1,high,multOrder); multOrder[multOrderNext]=k; multOrderNext++; } 举例: A1×A2×A3×A4 30×11×4040×1010×25 d0×d1d1×d2d2×d3d3×d4 注: 以下cost[i][j]用Cij表示,root[i][j]用Rij表示 C11=C22=C33=C44=0 C12=C11+C22+30×1×40=1200 R12=1 C23=C22+C33+1×40×10=400 R23=2 C34=C33+C44+40×10×25=10000 R34=3 C13=C11+C23+30×1×10=700ok C12+C33+30×40×10=13200 R13=1 C24=C22+C34+1×40×25=11000 C23+C44+1×10×25=650ok R24=3 C14=C11+C24+30×1×25=1400ok C12+C34+30×40×25>1400 C13+C44+30×10×25>1400 R14=1 所以最小代价C14=1400 10.给定长度为n的有序元素序列K1,K2,…,Kn,其各个元素被查找的概率(或频率)分别为p1,p2,…,pn。 描述构造最优二分树的算法 解答: 定义函数cost(low,high),表示用K(low)…K(high)构造得到的最优二分树的总代价,root(low,high)表示相应二分树的树根位置。 则状态转移方程为: 当low>high(low=high-1)时, 令cost(low,high=0) root(low,high)=-1 当low<=high时, cost(low,high)=p(low)+…+p(high)+min{cost(low,k-1)+cost(k+1,high)|low<=k<=high}式 (1) root(low,high)=k(式 (1)中对应cost(low,high)的k) 伪代码实现: 定义两个二维数组cost[1...n+1][0…n]和root[1…n+1][0…n] //初始化数组的对角线元素,即(t+1,t) for(i=1;i<=n+1;i++) cost[i][i-1]=0; root[i][i-1]=-1; //按一定的顺序填充数组 for(low=n;low>=1;low--) for(high=low;high<=n;high++) cost[low][high]=maxNum;//maxNum表示无穷大 for(k=low;k<=high;k++)//选取不同的元素作为当前树的树根 currentCost=low…high的概率和+cost(low,k-1)+cost(k+1,high) if(currentCost cost[low][high]=currentCost; root[low][high]=k; 最终,cost[1][n]即为最优二分树的代价。 对root数组进行先序遍历,即可得到最优二分树。 举例: C10=C21=C32=C43=C54=C65=C76=0 R10=R11=R22=R33=R44=C65=C76=-1 C66=C65+C76+2=2OKR66=6 C55=C54+C65+1=1OKR55=5 C56=C54+C66+3=5 C55+C76+3=4OKR56=6 C44=C43+C54+7=7OKR44=4 C45=C43+C55+8=9OKR45=4 C44+C65+8=15 C46=C43+C56+10=14OKR46=4 C44+C66+10=19 C45+C76+10=19 以下省略....... C16=C10+C26+25=63 C11+C36+25=52OKR16=2 最优二分树的建立 root[1][6]=2,所以2为树根,左子树有1,右子树有3-6; root[3][6]=4,所以4为树根,左子树有3,右子树有5-6; root[5][6]=6,所以6为树根,左子树有5,右子树为空 最后构成的最优二分树如图: 11.给出一个比较好的最大最小元算法。 基于思想: 对策论 两两结组,选出winner和loser。 winner里面找到最大的。 loser里面找到最小的。 具体分析: 元素个数n为偶数时: 结组比较: n/2次; 在n/2个winner中找到最大元: n/2-1; 在n/2个loser中找到最小元: n/2-1; 比较次数: C=(3n-4)/2; 具体分析: 元素个数n为奇数时(添加元素a[n]=a[n-1]): 结组比较: n-1/2次; 在n-1/2个winner中找到的最大元和a[n]选出最大元: (n-1/2)-1+1; 在n-1/2个loser中找到的最小元和a[n-1]选出最小元: (n-1/2)-1+1; 比较次数: C=(3n-3)/2; 12.同时找n个元素中最大与次大元素的好的算法,并说明你给出算法是好的理由。 13.n个元素找中间元素,3、5、7个元素一组时对应的时间复杂度分析 5个元素一组: 设从n个元素中找到指定位置的元素时间为W(n)。 从n个元素中找中间元素的步骤: 1): 5个元素一组对n个元素分组,一共分n/5组,从每一组中的5中找出中间元素要6次比较,时间总共: n/5*6; 2): 在n/5个组中间元素中再次找中间元素,时间为W(n/5)。 3): 通过1)、2),可粗略的得到元素的分别矩阵,矩阵的左上角的3n/10(3n/5*1/2)个元素均大于中间元素,右下角的3n/10(3n/5*1/2)个元素均小于中间元素。 剩余2n/5(1-3n/10-3n/10)个元素需与中间元素比较,以确定与中间元素的大小关系,时间为2/5n。 5个元素一组: 4): 2n/5个元素与当前中间元素比较,所用时间为2n/5。 比较结果最坏情况下为2n/5个元素均大于或小于当前中间元素。 5): 在2n/5+3n/10中找特定位置的元素,时间为W(7n/10)。 3个元素一组: 7个元素一组: 14.输入n个元素,输出m个最小的元素,其中(n>>m) (1)将所有n个元素放在数组A中从第n个位置开始的空间里(作为树的叶子),之后n个元素两两一组(A[i],A[i+1])进行比较,使用较小元素的索引作为这两个节点的父亲结点(A[i/2]),之后向上一次建树。 这样可以建立起一棵树T,T的内部结点都是索引值,叶子节点保存实际的数值。 (2)输出当前树T的根节点root指向的值,之后将该值设置成+∞,对树T中root指向的值从叶子节点到根节点经过的路径进行调整,使之满足父结点是两个儿子当中值较小者的索引。 (3)反复执行第2步,直到找够m个最小元素。 15.对于如下输入序列,画出红黑树的生成过程。 1,6,4,8,9,7,2,5,3 插入的结点 插入后的状况 操作步骤 1 黑 …… 6 黑红 …… 4 黑红红 s1: 变色(1变红,4变黑);s2: 反向(改为4指向1,并且4还要指向1); s3: 移儿子(4的左儿子变成1的右儿子,4的右儿子变成6的左儿子); s4: 移根(根由1变为4) 8 红黑红红 s1: 同层已存在的结点变色(1变黑,4变红,6变黑);s2: 抬根(4被抬高);s3: 变色(4变黑) 9 黑红红 s1: 变色(6变红,8变黑);s2: 反向(改为8指向6); s3: 移儿子(8的左儿子变成6的右儿子); s4: 移根(这一层的根由6变为8) 7 红黑红红 s1: 同层已存在的结点变色(6变黑,8变红,9变黑);s2: 抬根(8被抬高) 2 黑红 …… 5 红黑红 …… 3 黑红红 s1: 变色(1变红,2变黑);s2: 反向(改为2指向1); s3: 移儿子(2的左儿子变成1的右儿子); s4: 移根(这一层的根由1变为2) 16.红黑树证明: 高度为h的红黑树T的内部黑节点数至少为2^h-1 高度为h的红黑树T的内部节点数至多为4^h-1 任意黑色节点的深度最多是其黑色深度的2倍 设一个黑色节点的深度为h,即它到达根节点经过的边数为h,也就是说经过的节点数(包括根节点且不包括该黑色节点本身)为h。 由于红黑树中不会出现红色节点有红色的子节点,故每一个红色节点一定会连向至少一个黑色节点。 设所经过的红色节点数为x,黑色节点数为y,则x<=y,故h=x+y<=y+y=2y,而该黑色节点的黑色深度即为y,说明该黑色节点的深度h<=2y,即小于其黑色深度的2倍,命题得证。 红黑树应用 给定一个数组,元素长度高达n=10,000,000, 元素大小在32位整数以内, 再给定m=10,000,000个区间[0,r], 和一个整数k, 表示数组下标从0到r的所有元素中, 第k小的数是多少? (k满足1<=k<=r+1) 如果采用暴力解法,即对于每一个区间进行排序,然后直接选取第k小元素。 时间复杂度O(m*n*log(n)),最坏情况下操作次数高达2.3*10^15。 优化: 用红黑树来查找第k小元素。 考虑到红黑树是一颗基本平衡的二叉搜索树,利用二叉搜索树的性质我们可以很容易得到一个集合内的第k小元素是多少。 只需要在每个节点中记录以该节点为根的子树中节点个数即可。 从根节点作为当前节点开始查找第k小的元素,如果左孩子节点数等于k–1个,则当前节点即为所求元素,否则假设左孩子节点数为c个,如果c小于k-1个,则在右子树中查找第(k-1-c)小元素,否则在左子树中查找第k小元素。 如此处理,最终可以以O(logn)的复杂度查找第k小元素 这样做之后,发现如果直接每一个区间建立一个红黑树,复杂度仍为O(m*n*log(n)),考虑系数甚至比以前更差。 我们可以把区间按照右端点r排序,然后往红黑树里一个一个的插入元素,当红黑树里元素正好满足某个区间时求其解,可以将复杂度降低至O(m*log(m)+n*log(n)+m*log(n)),易知求解得顺序正好符号我们区间排序后的顺序。 16.动态数组规划 当需要增大数组时,将当前数组大小乘4,或者将当前数组大小乘2。 评价这两种方法
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 大连理工大学 算法 设计 讲解