[关闭]
@lunar 2016-03-14T19:30:21.000000Z 字数 2476 阅读 1285

HiHo一下 Week11 树中最长的路

HiHo


描述

上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中,小Ho发现他不仅仅可以拼凑成一棵二叉树!还可以拼凑成一棵多叉树——好吧,其实就是更为平常的树而已。

但是不管怎么说,小Ho喜爱的玩具又升级换代了,于是他更加爱不释手(其实说起来小球和木棍有什么好玩的是吧= =)。小Ho手中的这棵玩具树现在由N个小球和N-1根木棍拼凑而成,这N个小球都被小Ho标上了不同的数字,并且这些数字都是出于1..N的范围之内,每根木棍都连接着两个不同的小球,并且保证任意两个小球间都不存在两条不同的路径可以互相到达。总而言之,是一个相当好玩的玩具啦!

但是小Hi瞧见小Ho这个样子,觉得他这样沉迷其中并不是一件好事,于是寻思着再找点问题让他来思考思考——不过以小Hi的水准,自然是手到擒来啦!

于是这天食过早饭后,小Hi便对着又拿着树玩具玩的不亦乐乎的小Ho道:“你说你天天玩这个东西,我就问你一个问题,看看你可否知道?”

“不好!”小Ho想都不想的拒绝了。

“那你就继续玩吧,一会回国的时候我不叫上你了~”小Hi严肃道。

“诶!别别别,你说你说,我听着呢。”一向习惯于开启跟随模式的小Ho忍不住了,马上喊道。

小Hi满意的点了点头,随即说道:“这才对嘛,我的问题很简单,就是——你这棵树中哪两个结点之间的距离最长?当然,这里的距离是指从一个结点走到另一个结点经过的木棍数。”。

“啊?”小Ho低头看了看手里的玩具树,困惑了。

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为一个整数N,意义如前文所述。

每组测试数据的第2~N行,每行分别描述一根木棍,其中第i+1行为两个整数Ai,Bi,表示第i根木棍连接的两个小球的编号。

对于20%的数据,满足N<=10。

对于50%的数据,满足N<=10^3。

对于100%的数据,满足N<=10^5,1<=Ai<=N, 1<=Bi<=N

小Hi的Tip:那些用数组存储树边的记得要开两倍大小哦!

输出

对于每组测试数据,输出一个整数Ans,表示给出的这棵树中距离最远的两个结点之间相隔的距离。

样例

样例输入

8
1 2
1 3
1 4
4 5
3 6
6 7
7 8

样例输出

6

思路

这道题目可以用深度搜索地方法来。ans[i]表示以i为子树的树的直径(也就是最长路),在dfs过程中,m表示该节点的子节点中最深的,mm表示第二深的,那么ans[i]=m+mm+1。如果没有子节点或者如果仅有一个子节点,注意初始化m和mm为0的话,依旧是ans[i]=m+mm+1.

这里值得注意的是构建树的方法。题中给出的是每条边的信息,也就是没有指定根节点,那么每一个节点都可能是根节点,所以我们在构建的时候需要注意如果i是j的子节点,那么j也是i的子节点。

比较好的方法是用数组模拟邻接链表。
对照下面的代码来看:
header[i]表示节点i的第一个子节点在数组中的位置,若为0说明没有子节点。
node[i].to表示数组中i位置的节点的编号,node[i].next也就表示它的兄弟节点(有同样祖先)。
那么从i开始遍历,先找其第一个子节点header[i]node[header[i]].to即为其第一个子节点的编号,node[header[i]].next则为其第二个子节点在数组中的位置,利用i=node[i].next遍历,直到.next为0,说明所有子节点都已经遍历过了。
那么在构建数组的时候,每次插入边<from,to>的时候,就要把to插到node[header[from]]的最前面。

正如之前所说,i和j互为子节点,那么这道题遍历的时候需要加一个node[i].to!=formerP来防止遍历回去形成死循环(formerP表示遍历到当前结点是由formerP过来的,也就是说formerP是currP的父节点)。同理,在判断叶子节点的时候,我们将除了formerP之外没有子节点的节点认为是叶子结点。

代码

  1. #include <cstdio>
  2. #include <iostream>
  3. using namespace std;
  4. #define MAXN 100002
  5. struct tree_node{
  6. int to,next;
  7. }node[2*MAXN];
  8. int header[MAXN]; //header[x] represent Xth node's first child is node[header[x]]
  9. int p=1;
  10. int ans[MAXN+5]={0};
  11. void build(int to, int from){
  12. node[p].to=from; node[p].next=header[to];
  13. header[to]=p++;
  14. node[p].to=to; node[p].next=header[from];
  15. header[from]=p++;
  16. }
  17. //currP is current node & formerP means the former point
  18. int dfs(int currP,int formerP){
  19. if(node[header[currP]].to==formerP) {ans[currP]=1;return 1;}
  20. int i=header[currP];
  21. int m=0,mm=0;
  22. while(node[i].to){
  23. if(node[i].to!=formerP){
  24. int t=0;
  25. t=dfs(node[i].to,currP);
  26. if(t>=m){
  27. mm=m;m=t;
  28. }else{
  29. if(t>=mm){
  30. mm=t;
  31. }
  32. }
  33. }
  34. i=node[i].next;
  35. }
  36. ans[currP]=mm+m+1;
  37. return m+1;
  38. }
  39. int main(){
  40. int n;
  41. cin >> n;
  42. for(int i; i<(n-1); i++){
  43. int to ,from;
  44. cin >> to >> from;
  45. build(to,from);
  46. }
  47. dfs(1,-1);
  48. int out=0;
  49. for(int i=1;i<n+1;i++)if(ans[i]>out) out =ans[i];
  50. cout<< (out-1);
  51. return 0;
  52. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注