学习博客:https://www.cnblogs.com/ywjblog/p/9254997.html
树的直径
给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。后者通常也可称为直径,即直径是一个
数值概念,也可代指一条路径
树的直径通常有两种求法,时间复杂度均为O(n)。我们假设树以N个点N-1条边的无向图形式给出,并存储在邻接表中。
第一种是dp求法,在这里我只介绍bfs求法:
两次BFS(DFS)求树的直径
通过两次BFS或者两次DFS也可以求树的直径,并且更容易计算出直径上的具体节点
详细地说,这个做法包含两步:
1.从任意节点出发,通过BFS和DFS对树进行一次遍历,求出与出发点距离最远的节点记为p
2.从节点p出发,通过BFS或DFS再进行一次遍历,求出与p距离最远的节点,记为q。
从p到q的路径就是树的一条直径。因为p一定是直径的一端,否则总能找到一条更长的链,与直径的定义矛盾。显然地脑洞一下即可。p为直径的一端,那么自然的,与p最远的q就是直径的另一端。
在第2步的遍历中,可以记录下来每个点第一次被访问的前驱节点。最后从q递归到p,即可得到直径的具体方案
下面看一道例题:
题目链接:https://ac.nowcoder.com/acm/contest/884/A
链接:https://ac.nowcoder.com/acm/contest/884/A
来源:牛客网
meeting
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld
题目描述
A new city has just been built. There're nnn interesting places numbered by positive numbers from 111 to nnn.
In order to save resources, only exactly n−1n-1n−1 roads are built to connect these nnn interesting places. Each road connects two places and it takes 1 second to travel between the endpoints of any road.
There is one person in each of the places numbered x1,x2…xkx_1,x_2 ldots x_kx1,x2…xk and they've decided to meet at one place to have a meal. They wonder what's the minimal time needed for them to meet in such a place. (The time required is the maximum time for each person to get to that place.)
输入描述:
First line two positive integers, n,kn,kn,k - the number of places and persons.
For each the following n−1n-1n−1 lines, there're two integers a,ba,ba,b that stand for a road connecting place aaa and bbb. It's guaranteed that these roads connected all nnn places.
On the following line there're kkk different positive integers x1,x2…xkx_1,x_2 ldots x_kx1,x2…xk separated by spaces. These are the numbers of places the persons are at.
输出描述:
A non-negative integer - the minimal time for persons to meet together.
备注:
1≤n≤1051 leq n leq 10^51≤n≤105
题目大意:给你一颗树,树中某些结点上有人,问你这些人在全部在一点会面的最小是时间是多少
思路:显然就是求最远的两个关键点之间的距离了
看代码:
#include<iostream> #include<stack> #include<cstdio> #include<vector> #include<queue> #include<cstring> using namespace std; const int maxn=1e5+5; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 typedef long long LL; const LL INF=1e18; int cnt=0; int head[maxn],dis[maxn]; int a[maxn]; bool vis[maxn],key[maxn]; queue<int>q; struct E { int to,next; }edge[maxn<<1]; void add(int u,int v) { // cout<<"u:"<<u<<" v:"<<v<<endl; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt++; } void bfs(int x) { // cout<<"2:"<<vis[2]<<endl; vis[x]=true; dis[x]=0; q.push(x); while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(!vis[v]) { dis[v]=dis[u]+1; // cout<<"v:"<<v<<" dis[v]:"<<dis[v]<<endl; vis[v]=true;q.push(v); } } } } int main() { memset(head,-1,sizeof(head)); int N,K; cin>>N>>K; for(int i=1;i<N;i++) { int u,v;cin>>u>>v; add(u,v);add(v,u); } for(int i=1;i<=K;i++) { cin>>a[i];key[a[i]]=true;//标记是否为关键点 } bfs(a[1]);//任取一个关键点 // for(int i=1;i<=N;i++) cout<<dis[i]<<" ";cout<<endl; int ma=dis[a[1]],id=a[1]; for(int i=1;i<=N;i++)//找最远的关键点 { if(key[i]&&dis[i]>ma) { ma=dis[i];id=i; } } // cout<<"id:"<<id<<endl; memset(dis,0,sizeof(dis)); memset(vis,false,sizeof(vis)); bfs(id); // for(int i=1;i<=N;i++) cout<<dis[i]<<" ";cout<<endl; ma=-1; for(int i=1;i<=N;i++) { if(key[i]&&dis[i]>ma) { ma=dis[i]; } } cout<<(ma+1)/2<<endl; return 0; }