题解报告:hihoCoder #1050 : 树中的最长路
描述
上回说到,小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
解题思路:题意:有n个点,它们之间有n-1条无向边,形成一棵树,并且保证任意两个点间都不存在两条不同的路径可以互相到达。求这棵树中哪两个结点之间的距离最长?这里的距离是指从一个结点走到另一个结点经过的边数。
求树的直径(最长路),也就是图中某两点的最长距离。做法:随便以某一个点开始dfs(bfs)找到深度最大的便是直径的某一端点t,然后从这个点t再dfs(bfs)一次就可以找出直径的另一端点s,这样s---t就是树的直径,也就是常说的树上最长路。为什么可以随便以一个点开始就能找到直径的某一端点呢?请看这篇博文(不难理解):树的直径最长路证明。
AC代码一(129ms):两次dfs。时间复杂度为0(2E)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+;
vector<int> vec[maxn];
int n,u,v,maxdep,maxvex;bool vis[maxn];
void dfs(int x,int dep){
vis[x]=true;
int sz=vec[x].size();
if(sz==&&dep>maxdep){maxdep=dep;maxvex=x;}//找到离当前根节点最远的叶子节点,更新深度值和叶子节点编号
for(int i=;i<sz;++i)//遍历其邻接点
if(!vis[vec[x][i]])dfs(vec[x][i],dep+);
}
int main(){
while(~scanf("%d",&n)){
for(int i=;i<=n;++i)vec[i].clear();
while(--n){
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
maxdep=,maxvex=;
memset(vis,false,sizeof(vis));
dfs(,);//第一次随便以某个点为根节点,找树的直径的某一端点maxvex
memset(vis,false,sizeof(vis));maxdep=;
dfs(maxvex,);//第二次从maxvex去找树直径的另一端点
printf("%d\n",maxdep);
}
return ;
}
AC代码二(89ms):两次bfs。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+;
struct EDGE{int to,next;}edge[maxn<<];
struct node{
int u,dep;
node(int x,int y):u(x),dep(y){}
};
int n,x,y,cnt,res,maxdep,maxvex,head[maxn];bool vis[maxn];
queue<node> que;
void add_edge(int u,int v){
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void bfs(int u,int dep,int &maxdep,int &maxvex){
while(!que.empty())que.pop();
memset(vis,false,sizeof(vis));
que.push(node(u,dep));vis[u]=true;
while(!que.empty()){
node nod=que.front();que.pop();
for(int i=head[nod.u];~i;i=edge[i].next){
int v=edge[i].to;
if(!vis[v]){
vis[v]=true;
que.push(node(v,nod.dep+));
}
}
if(maxdep<nod.dep)maxdep=nod.dep,maxvex=nod.u;//取最深
}
}
int main(){
while(~scanf("%d",&n)){
memset(head,-,sizeof(head));cnt=;
while(--n){
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
maxdep=,maxvex=;
bfs(,,maxdep,maxvex);maxdep=0;
bfs(maxvex,,maxdep,maxvex);
printf("%d\n",maxdep);
}
return ;
}
AC代码三(79ms):一次dfs。这里用到了一个树的性质:树的直径的长度一定会是某个点t的最长距离first(t)与次长距离second(t)之和。最后求出max{first(t),second(t)}就可以了。如果用first(t),second(t)分别表示以t为根节点的子树中最长路和次长路的长度,那么只需要求出t的所有子结点的first值,first(t)便是这些first值中的最大值+1,second(t)便是这些first值中的次大值+1。时间复杂度为O(E)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+;
struct node{int to,next;}edge[maxn<<];//无向图双向边,2倍边数
int n,x,y,cnt,res,head[maxn];
void add_edge(int u,int v){//链式前向星
edge[cnt].to=v;
edge[cnt].next=head[u];//第cnt条边记录上一次起点为u的边的编号
head[u]=cnt++;//head[u]表示当前以u为起点的第cnt条边
}
int dfs(int u,int fa,int &maxdist){
int Dmax=,Dsec=;//每一个子树的根节点都有一个最长距离和次长距离,因此要重新定义,不然会出错
for(int i=head[u];~i;i=edge[i].next){
//printf("第%d条边\n",i/2);
int v=edge[i].to;//取出子树节点
//cout<<"fa:"<<fa<<",u:"<<u<<",v:"<<v<<endl;
if(v^fa){//避免再次遍历到父节点
//cout<<"u:"<<u<<' '<<"v:"<<v<<endl;
int nowd=dfs(v,u,maxdist)+;
if(nowd>Dmax)Dsec=Dmax,Dmax=nowd;
else if(nowd>Dsec)Dsec=nowd;
//求出t的所有子结点的Dmax(first)值,first(t)便是这些first值中的最大值+1,second(t)便是这些first值中的次大值+1.
//cout<<u<<"--->"<<v<<"、子树的最长深度:"<<nowd<<",第一长:"<<Dmax<<",第二长:"<<Dsec<<endl;
}
}
maxdist=max(maxdist,Dmax+Dsec);//更新树的直径:最长+次长
//cout<<"目前最长的距离"<<maxdist<<endl;
return Dmax;//返回当前以u为根的子树中的最大深度
}
int main(){
while(~scanf("%d",&n)){
memset(head,-,sizeof(head));cnt=;
while(--n){
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
int maxlen=;
dfs(,-,maxlen);
printf("%d\n",maxlen);
}
return ;
}
/**
样例模拟过程如下:
8
1 2
1 3
1 4
4 5
3 6
6 7
7 8
第2条边
fa:-1,u:1,v:4
u:1 v:4
第3条边
fa:1,u:4,v:5
u:4 v:5
第3条边
fa:4,u:5,v:4
目前最长的距离0
4--->5、子树的最长深度:1,第一长:1,第二长:0
第2条边
fa:1,u:4,v:1
目前最长的距离1
1--->4、子树的最长深度:2,第一长:2,第二长:0
第1条边
fa:-1,u:1,v:3
u:1 v:3
第4条边
fa:1,u:3,v:6
u:3 v:6
第5条边
fa:3,u:6,v:7
u:6 v:7
第6条边
fa:6,u:7,v:8
u:7 v:8
第6条边
fa:7,u:8,v:7
目前最长的距离1
7--->8、子树的最长深度:1,第一长:1,第二长:0
第5条边
fa:6,u:7,v:6
目前最长的距离1
6--->7、子树的最长深度:2,第一长:2,第二长:0
第4条边
fa:3,u:6,v:3
目前最长的距离2
3--->6、子树的最长深度:3,第一长:3,第二长:0
第1条边
fa:1,u:3,v:1
目前最长的距离3
1--->3、子树的最长深度:4,第一长:4,第二长:2
第0条边
fa:-1,u:1,v:2
u:1 v:2
第0条边
fa:1,u:2,v:1
目前最长的距离3
1--->2、子树的最长深度:1,第一长:4,第二长:2
目前最长的距离6
6
**/

题解报告:hihoCoder #1050 : 树中的最长路的更多相关文章
- hihocoder 1050 树中的最长路(动态规划,dfs搜索)
hihocoder 1050 树中的最长路(动态规划,dfs搜索) Description 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中,小Ho发现他不仅 ...
- hihocoder#1050 : 树中的最长路(树中最长路算法 两次BFS找根节点求最长+BFS标记路径长度+bfs不容易超时,用dfs做TLE了)
#1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中, ...
- hihoCoder 1050 树中的最长路 最详细的解题报告
题目来源:树中的最长路 解题思路:枚举每一个点作为转折点t,求出以t为根节点的子树中的‘最长路’以及与‘最长路’不重合的‘次长路’,用这两条路的长度之和去更新答案,最终的答案就是这棵树的最长路长度.只 ...
- hihoCoder #1050 : 树中的最长路
题意: 求出树上最长路径的长度,并返回. 思路: 刚看到数据<=10^5,假如是单分支的树,那么有5万层,就不能递归,那就用桟实现, 那就要将长度信息保存在另开的数组中,很麻烦!!这题专门给递归 ...
- hiho #1050 : 树中的最长路 树的直径
#1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中, ...
- [HIHO] 1050 树中的最长路
#1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中, ...
- hihoCoder week11 树中的最长路
题目链接: https://hihocoder.com/contest/hiho11/problem/1 求树中节点对 距离最远的长度 #include <bits/stdc++.h> u ...
- HihoCoder第十一周:树中的最长路
#1050 : 树中的最长路 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上回说到,小Ho得到了一棵二叉树玩具,这个玩具是由小球和木棍连接起来的,而在拆拼它的过程中, ...
- 题解【洛谷P1807】最长路_NOI导刊2010提高(07)
题面 题解 最长路模板. 只需要在最短路的模板上把符号改一下\(+\)初值赋为\(-1\)即可. 注意一定是单向边,不然出现了正环就没有最长路了,就好比出现了负环就没有最短路了. 只能用\(SPFA\ ...
随机推荐
- My app status is Ready for Sale but I cannot see my app on the App Store. Why? 为什么审核通过后 appstore中搜不到我的app
这是苹果的官方解答 The following factors could prevent your app from showing up on the App Store: Make sure t ...
- 编译异常之static和extern---more than one storage class specified
static 和 extern 不能同时共存 http://bbs.bccn.net/thread-58129-1-1.html
- subclassdlgitem
subclassdlgitem 该函数用来子类化一个控件. Subclass(子类化)是MFC中最常用的窗体技术之一.子类化完成两个工作:一是把窗体类对象attach到一个windows窗体实体中(即 ...
- 我遇到的错误curl: (7) Failed to connect to 127.0.0.1 port 1086: Connection refused
今天我用curl命令,无论如何都是出现: curl: (7) Failed to connect to 127.0.0.1 port 1086: Connection refused 找了很久,不知道 ...
- bzoj4103: [Thu Summer Camp 2015]异或运算
对于每个询问暴力枚举x~y,然后在Trie去找第k大,开始我写了个二分答案然后算比当前答案大的个数,打了个第10个点的表就跑出19s+比bzoj垫底还慢4s+ 然而不用二分,直接1000个点一起在树上 ...
- 百度地图API--信息窗口
信息窗口 -----纯文本信息窗口 为了更方便的提示用户,在地图的指定的地方添加文本信息的窗口,给用户直观展示信息,下面是如何添加一个纯文本的信息窗口. 下面是添加一个文本窗口: /* * 添加纯文本 ...
- BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS
BZOJ_3073_[Pa2011]Journeys_线段树优化建图+BFS Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N ...
- 【ZJOI 2008】树的统计
[题目链接] 点击打开链接 [算法] 树链剖分模板题 [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 3000 ...
- 多线程-threading模块3
超级播放器 #coding:utf-8 import threading from time import sleep,ctime #超级播放器 def super_player(file,time) ...
- 【转】git修改文件后,提交到远程仓库
原文地址:https://blog.csdn.net/nly19900820/article/details/73613654 修改文件后,怎么提交到远程仓库1.git status 查看git是否有 ...