树上某点距离最远的结点

题目链接

题目需要得到树上每个结点出发可到达的最远的结点,顺便求出树的直径。

这里顺便总结一下求解的两种方法。

第一种思路:三种dfs(bfs)

  第一遍dfs(bfs)从任意结点出发,找到距离该结点最远的结点u(直径的端点之一)。

  第二遍dfs(bfs)从u出发,求出其他点到u的距离,最长的即为v(直径的另一个端点)。
  第三遍dfs(bfs)从v出发,求出其他点到v的距离。
  可以知道,对于任意结点x,其在树上可到达的最远的距离为max{dist[x][u], dist[x][v]}.
  故其最大值即为树的直径。这样,就可以满足题目需求了。
第二种思路:树dp(两次不同的dfs)
  首先,该种方法需要记录每个结点到以其为根的子树中所以结点距离的最大值f[x]和次大值g[x].
  这个可以由第一次dfs得到(以任意结点为根)。
  第二次dfs就是一个树dp, 需要得到每个结点可以到达的最远距离far[x].
  这里,树的直径即为max{fax[x]}. 当然,也可以根据树的直径diam = max{f[x] + g[x]}得到。
最后附上代码:
第一种:
 1 /*************************************************************************
 2     > File Name: 19C.cpp
 3     > Author: Stomach_ache
 4     > Mail: [email protected]
 5     > Created Time: 2014年12月01日 星期一 18时31分41秒
 6     > Propose: 树的直径以及树上某点能到达的最远结点
 7  ************************************************************************/
 8 #include <queue>
 9 #include <cmath>
10 #include <string>
11 #include <vector>
12 #include <cstdio>
13 #include <fstream>
14 #include <cstring>
15 #include <iostream>
16 #include <algorithm>
17 using namespace std;
18 /*Let‘s fight!!!*/
19
20 const int MAX_N = 100050;
21 const int INF = 0x3f3f3f3f;
22 typedef long long LL;
23 #define rep(i, n) for (int i = (0); i < (n); i++)
24 vector<int> G[MAX_N];
25 int distA[MAX_N], distB[MAX_N];
26 bool vis[MAX_N];
27
28 void bfs(int s, int *dist) {
29     fill(dist, dist + MAX_N, -INF);
30     queue<int> Q;
31     Q.push(s);
32     dist[s] = 0;
33     while (!Q.empty()) {
34         int now = Q.front(); Q.pop();
35         vis[now] = true;
36         int sz = G[now].size();
37         for (int i = 0; i < sz; i++) {
38             int nxt = G[now][i];
39             if (!vis[nxt]) {
40                 Q.push(nxt);
41                 dist[nxt] = dist[now] + 1;
42             }
43         }
44     }
45 }
46
47 int main(void) {
48     int N, M;
49     scanf("%d %d", &N, &M);
50     rep (i, N-1) {
51         int u, v;
52         scanf("%d %d", &u, &v);
53         G[u].push_back(v);
54         G[v].push_back(u);
55     }
56
57     bfs(1, distA);
58     int u = 1;
59     for (int i = 2; i <= N; i++) if (distA[i] > distA[u]) u = i;
60
61     memset(vis, false, sizeof(vis));
62     bfs(u, distA);
63     int v = 1;
64     for (int i = 2; i <= N; i++) if (distA[i] > distA[v]) v = i;
65
66     memset(vis, false, sizeof(vis));
67     bfs(v, distB);
68     LL diam = distA[v];
69     while (M--) {
70         int v, k;
71         scanf("%d %d", &v, &k);
72         printf("%lld\n", diam * (k - 1) + max(distA[v], distB[v]));
73     }
74     return 0;
75 }

第二种:

 1 /*************************************************************************
 2     > File Name: 19C_dp.cpp
 3     > Author: Stomach_ache
 4     > Mail: [email protected]
 5     > Created Time: 2014年12月01日 星期一 19时02分44秒
 6     > Propose:
 7  ************************************************************************/
 8
 9 #include <cmath>
10 #include <string>
11 #include <cstdio>
12 #include <vector>
13 #include <fstream>
14 #include <cstring>
15 #include <iostream>
16 #include <algorithm>
17 using namespace std;
18 /*Let‘s fight!!!*/
19
20 const int MAX_N = 100050;
21 const int INF = 0x3f3f3f3f;
22 typedef long long LL;
23 vector<int> G[MAX_N];
24 int dp[2][MAX_N], far[MAX_N];
25
26 void dfs(int u, int fa) {
27     int sz = G[u].size();
28     for (int i = 0; i < sz; i++) {
29         int v = G[u][i];
30         if (v != fa) {
31             dfs(v, u);
32             if (dp[0][v] + 1 > dp[0][u]) {
33                 dp[1][u] = dp[0][u];
34                 dp[0][u] = dp[0][v] + 1;
35             } else if(dp[0][v] + 1 > dp[1][u]) {
36                 dp[1][u] = dp[0][v] + 1;
37             }
38         }
39     }
40 }
41
42 void dfs2(int u, int fa, int up) {
43     int sz = G[u].size();
44     far[u] = max(dp[0][u], up);
45     for (int i = 0; i < sz; i++) {
46         int v = G[u][i];
47         if (v != fa) {
48             if (dp[0][v] + 1 == dp[0][u]) dfs2(v, u, max(up, dp[1][u])+1);
49             else dfs2(v, u, max(up, dp[0][u])+1);
50         }
51     }
52 }
53
54 int main(void) {
55     int N, M;
56     scanf("%d %d", &N, &M);
57     for (int i = 0; i < N - 1; i++) {
58         int u, v;
59         scanf("%d %d", &u, &v);
60         G[u].push_back(v);
61         G[v].push_back(u);
62     }
63
64     dfs(1, -1);
65     dfs2(1, -1, 0);
66
67     LL diam = 0;
68     //两者等价
69     //for (int i = 1; i <= N; i++) if (dp[0][i] + dp[1][i] > diam) diam = dp[0][i] + dp[1][i];
70     for (int i = 1; i <= N; i++) if (far[i] > diam) diam = far[i];
71     while (M--) {
72         int v, k;
73         scanf("%d %d", &v, &k);
74         printf("%lld\n", diam * (k - 1) + far[v]);
75     }
76     return 0;
77 }
时间: 2024-10-14 09:55:29

树上某点距离最远的结点的相关文章

编程之美-2.11 扩展 寻找距离最远的两个点

一.问题描述 平面上有n个点,如何寻找距离最远的两个点? 二.解题思路 第一步,寻找凸包(因为最远距离的两个点一定在凸包上) 第二步,用旋转卡(qia)壳 寻找距离最大的点 凸包和旋转卡壳算法参见http://blog.csdn.net/kaytowin/article/details/5140111 三.代码实现 #include<iostream> #include<vector> #include<algorithm> #include<cmath>

POJ 1986 Distance Queries LCA树上两点的距离

题目来源:POJ 1986 Distance Queries 题意:给你一颗树 q次询问 每次询问你两点之间的距离 思路:对于2点 u v dis(u,v) = dis(root,u) + dis(root,v) - 2*dis(roor,LCA(u,v)) 求最近公共祖先和dis数组 #include <cstdio> #include <cstring> #include <vector> using namespace std; const int maxn =

HDU 4612 Warm up(手动扩栈,求树上哪两个点的距离最远)

题目大意: 给你一个无向图,问加一条边之后最少还剩下几座桥. (注意重边处理) 分析:其实当我们把边双连通分量给求出来之后我们就能将连通块求出来,这样我们就可以重新构图.重新构造出来的图肯定是一颗树了, 那么问题就转化为求树的哪两个节点的距离最长.我们可以随便找一个点S开始BFS, BFS到这个点最远的那个点P,然后再从这个最远点P开始BFS,BFS到P最远的点E,  PE之间的距离就是这个图上最大的距离. 注:此题需要手动扩栈 #pragma comment(linker, "/STACK:1

cdoj 92 Journey tarjan/lca 树上点对距离

Journey Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/92 Description Bob has traveled to byteland, he find the N cities in byteland formed a tree structure, a tree structure is very special structure, there is exa

距离最远的牛

所以说oj上总是不会没了牛 所以我们就可以看出john和他的奶牛是多么活泼了,上一个这么活泼的是蓝精灵和格格巫-..不管怎么讲题还是要写的,那么下面我们就看看这道题的解题思路. 简单的二维题基本,枚举每头奶牛的位置,计算出他们之间的距离,求最大的值,并记录此时奶牛的编号,和奶牛的相似度类似,可参考奶牛的相似度 下面发一下我的代码: #include <iostream> #include <iomanip> #include <cmath> #include <s

HDU2376Average distance(树形dp|树上任意两点距离和的平均值)

思路: 引:如果暴力枚举两点再求距离是显然会超时的.转换一下思路,我们可以对每条边,求所有可能的路径经过此边的次数:设这条边两端的点数分别为A和B,那 么这条边被经过的次数就是A*B,它对总的距离和的贡献就是(A*B*此边长度).我们把所有边的贡献求总和,再除以总路径数N*(N-1)/2,即为最 后所求. 每条边两端的点数的计算,实际上是可以用一次dfs解决的.任取一点为根,在dfs的过程中,对每个点k记录其子树包含的点数(包括其自身),设点数为a[k],则k的父亲一侧的点数即为N-a[k].这

Leetcode 863--二叉树中所有距离为 K 的结点

首先找到每个节点的父节点,利用map存储(map底层用红黑树实现,所以查找效率也高),这种方法客服了二叉树只能找到自己的儿子的缺点. 然后用dfs搜索的方法寻找目标节点. 代码如下: class Solution {public: map<TreeNode*,TreeNode*> par; void findparent(TreeNode* root){ if(!root) return; if(root->left){ par[root->left]=root; findpare

【tyvj1520】 树的直径

描述 Description 树的直径,即这棵树中距离最远的两个结点的距离.每两个相邻的结点的距离为1,即父亲结点与儿子结点或儿子结点与父子结点之间的距离为1.有趣的是,从树的任意一个结点a出发,走到距离最远的结点b,再从结点b出发,能够走的最远距离,就是树的直径.树中相邻两个结点的距离为1.你的任务是:给定一棵树,求这棵树中距离最远的两个结点的距离. 输入格式 InputFormat 输入共n行第一行是一个正整数n,表示这棵树的结点数接下来的n-1行,每行三个正整数a,b,w.表示结点a和结点

CodeVS 1020孪生蜘蛛

虽然最近最短路写的挺熟练的,但这道题还是坑了我两个小时..   题目大意:在一个无向图里找两个结点使在除了这两个结点以外的任意一个结点到这两个结点的权值最小.(距离为出发结点到两     个结点的最小权值).   算法:Floyd+枚举(SPFA蜜汁TLE..)      首先这道题读了好几遍都不知道它要求什么(题意好迷啊..),一直不明白什么叫最坏情况下的最优解,按自己的理解打了spfa,交    上去全wa..于是按着wa的数据手动画了个图,然后跟着答案去推,才发现是求一波最短路再枚举两个点