问答题 自由树(即无环连通图)T=(V,E)的直径是树中所有点对点之间最短路径长度的最大值,即T的直径定义为d(u,v)的最大值(其中u,v∈V)。这里d(u,v)表示顶点u到顶点v的最短路径长度(路径长度为路径中包含的边数)。如图所示为一棵自由树,其直径为18。试写算法求T的直径,并分析算法的时间复杂度。
【正确答案】利用深度优先遍历求出一个根结点v到每个叶子结点的距离,这是由diameter(v)函数实现的。该函数的时间复杂度为O(n+e),n为顶点个数,e为边数。然后,以每个顶点作为根结点调用diameter()函数,其中最大值即为T的直径,本算法的时间复杂度为O(n(n+e))。 实现本题功能的程序代码如下: void dfs(int parent,int child,int &len) //函数执行结束后,len中存放从根结点到child结点所在子树的叶子结点的最大距离 //cost是带权邻接矩阵,visited是已经初始化的访问标记数组 //N是已定义的常量,即顶点个数 { int clen,v=0,maxlen; clen=len; maxlen=len; while(v<N && cost[child][v]==0) //找与child相邻的第一个顶点v v++; while(v<N) //存在邻接顶点时循环 { if(v!=parent) { len=len+cost[child][v]; dfs(child,v,len); if(len>maxlen) maxlen=len; } v++; while(v<N && cost[child][v]==0) //找与child相邻的下一个顶点v v++; len=clen; } len=maxlen; } int diameter(int v) { int maxlen1=0; //存放到目前为止所找到的根v到叶子结点的最大值 int maxlen2=0; //存放到目前为止所找到的根v到叶子结点的次大值 int len=0; //记录深度优先遍历中到某个叶子结点的距离 int w=0; //存放v的邻接顶点 while(w<N && cost [v][w]==0) //找与v相邻的第一个顶点w w++; while(w<N) //存在邻接顶点时循环 { len=cost[v][w]; dfs(v,w,len); if(len>maxlen1) { maxlen2=maxlen1; maxlen1=len; } else if(len>maxlen2) maxlen2=len; w++; while(w<N && cost [v][w]==0) //找与v相邻的第一个顶点w w++; } return maxlen1+maxlen2; } for(i=1;i<N;i++) //找出从所有顶点出发直径的最大值 { d=diameter(i); if(diam<d) diam=d; }
【答案解析】[说明] 本题提到最短路径,拿到题目后,考生容易将其归类为最短路径问题,而去想相应的算法。但由于本题限定图为自由树,所以只需用深度优先搜索的方法即可得到每两点的最短路径。这种在题目中设置干扰因素的情况在正式考题中是常见的,因此考生必须注意区分,以提高做题效率。