树的直径问题
题目描述
给定一棵树,求树的直径,树的直径被定义为树中任意两点之间的距离的最大值,树的边权都为1
做法
首先明确树的直径一定是某两个叶子之间的距离
从树中任选一个点开始遍历这棵树,找到距离这个点最远的叶子,然后在从这个叶子开始遍历,找到里这个叶子最远的另一个叶子,他俩之间的距离就是树的直径。
两次遍历就可以求得树的直径
遍历可以使用DFS、BFS,找到距离起点最远的叶子节点就好。
题目描述
给定一棵树,输出n个数,第i个数表示第i个点到其他任意一点的最长距离。树的边权是1
这个例子中答案:3 2 3 4 4
首先回忆求树的直径的方法,假设树的最长路的两个叶子节点为v1,v2,从任意一点u出发走到最远点一定是(v1,v2)中的一点,然后再从v1或v2出发,走到最远点一定是v2或者v1,由此经过两此遍历就能找到最长路径。
某个节点x的最长路径要么是到v1的路径,要么是到v2的路径。
那么需要三次遍历,一次是从根出发,走到v1,从v1出发记录每个点距离v1点的距离。
记录下v2点,从v2点开始遍历,再记录下最长的距离。
三次遍历就额可以求解。
CSP-201403-4无线网路
如果没有K的限制,那么就可以把m个位置都放上路由器,只要是两个路由器之间的距离不超过r,连个路由器就可以连一条边,那么就可以建立网络
求图中两个点之间的距离,途中所有变得权值为1
进行BFS,第一次遇到终点时求的距离便是两者之间的最短路。
现在加上k的限制。
我们将路由器分成两部分,一部分已经放好的路由器,一部分受k限制的路由器。
我们再进行BFS遍历的时候,可以记录下从源点,遍历到这个点的时候已经添加了几个受限路由器。
如果走到该点的时候,已经走了K个受限的路由器,紧接着之后就在遍历该点的邻接点时,就不能走受限路由器了。
走完bfs就是结果。
例题:
树的直径的应用
你现在是城市的主人
现在有 n 个村庄,已经修建了 n-1 条道路,使得各个村庄作为节点,路作为边,构成一棵树。
假设第 a 个村庄到第 b 个村庄有路相连,则从 a 走到 b 或者从 b 走到 a 需要走 1m 。
你需要输出 n 个数,第 i 个数代表从第 i 个村庄出发,距离他最远的村庄的距离
思路: 找到树的直径,到任意村庄的距离,就是到某一直径的距离。
一次dfs,找到一个直径的端点,从该端点出发,进行dfs将每个节点到该端点的距离记录到数组中。同时找到另一个端点。从另一个端点出发,再次dfs,更新数组中的值。
结果输出数组
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100015
//使用链式前向星进行存储
struct Edge{
int u,v,w,nxt;
}Edges[2*MAXN];
int head[MAXN], tot,cnt_max = 0,far_left;//tot 是Edges的下标
bool vis[MAXN];
int dis[MAXN];
void init(int n)
{
tot = 0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v,int w){
Edges[tot].u = u;
Edges[tot].v = v;
Edges[tot].w = w;
Edges[tot].nxt = head[u];
head[u] = tot;
tot++;
}
//链式前向星dfs遍历
void dfs(int u,int cnt){
for(int i=head[u];i!=-1; i=Edges[i].nxt)
{
if(!vis[Edges[i].v])
{
vis[Edges[i].v] = true;
dfs(Edges[i].v,cnt+1);
}
}
if(cnt_max < cnt)
{
cnt_max = cnt;
far_left = u;
}
if(cnt > dis[u])
dis[u] = cnt;
}
int main()
{
//freopen("6_a.in","r",stdin);
//freopen("6_a.out","w",stdout);
int n,a,b;
cin>>n;
init(n);
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
for(int i=0;i < n-1;i++)
{
cin>>a>>b;
//道路双向
addEdge(a,b,1);
addEdge(b,a,1);
}
vis[1] =1;
dfs(1,0);
int v1 = far_left;
memset(vis,0,sizeof(vis));
vis[v1]=1;
dfs(v1,0);
int v2 = far_left;
memset(vis,0,sizeof(vis));
vis[v2]=1;
dfs(v2,0);
for(int i=1;i <= n;i++)
cout<<dis[i]<<" ";
cout<<endl;
return 0;
}