@lunar
2016-03-15T03:30:21.000000Z
字数 2476
阅读 1392
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之外没有子节点的节点认为是叶子结点。
#include <cstdio>
#include <iostream>
using namespace std;
#define MAXN 100002
struct tree_node{
int to,next;
}node[2*MAXN];
int header[MAXN]; //header[x] represent Xth node's first child is node[header[x]]
int p=1;
int ans[MAXN+5]={0};
void build(int to, int from){
node[p].to=from; node[p].next=header[to];
header[to]=p++;
node[p].to=to; node[p].next=header[from];
header[from]=p++;
}
//currP is current node & formerP means the former point
int dfs(int currP,int formerP){
if(node[header[currP]].to==formerP) {ans[currP]=1;return 1;}
int i=header[currP];
int m=0,mm=0;
while(node[i].to){
if(node[i].to!=formerP){
int t=0;
t=dfs(node[i].to,currP);
if(t>=m){
mm=m;m=t;
}else{
if(t>=mm){
mm=t;
}
}
}
i=node[i].next;
}
ans[currP]=mm+m+1;
return m+1;
}
int main(){
int n;
cin >> n;
for(int i; i<(n-1); i++){
int to ,from;
cin >> to >> from;
build(to,from);
}
dfs(1,-1);
int out=0;
for(int i=1;i<n+1;i++)if(ans[i]>out) out =ans[i];
cout<< (out-1);
return 0;
}