树(1)最长边树

赛车

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

幻想乡有一个赛车场。赛车场里有N个地点。同时地点之间还有单向的道路存在。

这些道路使得赛车场形成了一个外向树的结构。也就是说,道路将这N个地点连成了一个有根树。并且所有的边都是从父亲指向孩子的。

由于幽香喜欢刺激,每次她去赛车场都会从根节点出发,选择最长的一条路径来玩。

但是现在幽香感觉最长的路径还是太短了,她打算在赛车场里新建一条道路使得新的最长路径最长。

同时,如果道路形成了一个环,那么可能会出现交通事故,所以幽香新建的道路不能导致环的出现。

你能帮幽香算出新建一条道路后的最长路径吗?幽香知道根节点一定是1号点。

输入

一行一个数N,表示地点的数量。

接下来N-1行,每行两个数a和b,表示从点a到点b有一条单向路径。所有点从1到n标号。

数据范围:

n<=100000。

输出

一行表示新建一条边后的最长路径。

样例输入
5
1 2
2 3
1 4
4 5
样例输出
4

首先遍历一棵树,dis[x]表示从x节点开始一条边上最多的节点数(包括x节点),比如1 2 ,2 3,dis[1] = 3,dis[2] = 2,dis[3] = 1。
自然,dis[1]就是最多边的节点数。
然后,再搜索一遍,将最多边上的节点标记vis[x] = 1;
再对没有标记过的节点vis[x] = 0,进行比较他们的dis[x]值,自然,找到最大的,便是要连的节点。
最后节点数-1便是answer。
#include<cstdio>
#include<vector>
#include<algorithm>
const int maxn = 1e5+5;
using namespace std;
vector<int>vec[maxn];
int dis[maxn];
bool vis[maxn];
int n;
int build(int x){
    if(vec[x].size()==0)
        return 1;//没有子节点了,反馈该节点数,也就是1。
    for(int i = 0; i < vec[x].size(); i++)
    dis[x] = max(dis[x],build(vec[x][i])+1);//进行标记,找出最大dis[x];"+1"就是加x本身的节点数,自然是1。
    return dis[x];
}
//从1开始进行搜索,根据最大的dis[x]进行进一步搜索,并且对每个搜索到的节点进行标记vis[x] = 1。
void findl(int x){ vis[x] = 1; if(vec[x].size()==0) return; int t = 0; for(int i = 1; i < vec[x].size(); i++){ if(dis[vec[x][i]] > dis[vec[x][t]]) t = i; } findl(vec[x][t]); } int main(){ int u,v; while(~scanf("%d",&n)){
    //初始化。
for(int i = 1; i <= n; i++){ vec[i].clear(); dis[i] = 0; vis[i] = 0; }
     //vector。
for(int i = 1; i < n; i++){ scanf("%d%d",&u,&v); vec[u].push_back(v); } int ans = build(1); findl(1); int maxx = 0;
     //对没有标记的节点进行比较,找出最大dis[x]。
for(int i = 1; i <= n; i++){ if(!vis[i]) maxx = max(maxx,dis[i]); } printf("%d\n",ans+maxx-1); } return 0; }

 

posted @ 2015-08-31 16:33  Tobu  阅读(176)  评论(0)    收藏  举报