树上某点距离最远的结点

题目链接

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

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

第一种思路:三种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: sudaweitong@gmail.com
 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: sudaweitong@gmail.com
 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 }

转载于:https://www.cnblogs.com/Stomach-ache/p/4135896.html

### 计算二叉树中的结点个数 为了计算二叉树中的结点个数,可以采用递归的方式遍历整棵树。对于每一个访问到的结点,增加计数值直到遍历结束。 ```python def count_nodes(root): if root is None: return 0 return 1 + count_nodes(root.left) + count_nodes(root.right) ``` 此方法通过递增方式累加每个被访问过的节数目从而得出总数[^1]。 ### 输出二叉树b的叶子结点个数 针对获取叶子结点的数量,则需特别注意那些既无左孩子也无右孩子的结点。每当遇到这样的结点时便将其计入最终的结果之中。 ```python def count_leafs(root): if root is None: return 0 elif root.left is None and root.right is None: return 1 else: return count_leafs(root.left) + count_leafs(root.right) ``` 上述代码实现了当检测到当前处理的是叶节(即左右子节皆为空),则返回1;反之继续向下一层探索直至完成整个树形结构扫描[^2]。 ### 求二叉树b中指定结点值的结点的层次 寻找给定值所在层的位置可以通过广度优先搜索(BFS),因为BFS能够按照从上至下的顺序逐级检查各层内的所有元素。一旦发现目标对象立即停止并记录下此时所处层数作为答案输出。 ```python from collections import deque def find_node_level(root, target_val): queue = deque([(root, 1)]) while queue: node, level = queue.popleft() if not node: continue if node.val == target_val: return level queue.append((node.left, level + 1)) queue.append((node.right, level + 1)) return -1 # 如果找不到该节,则返回-1表示不存在 ``` 这段逻辑利用队列辅助存储待考察的对象及其对应的高度信息,在每次迭代过程中更新这些数据以便于后续操作。 ### 利用层次遍历求二叉树b的宽度 最大宽度指的是同一水平线上最多含有的非空结点数量。因此同样适用基于队列实现的层次遍历策略,并在此基础上维护一个变量用于跟踪每一轮次的最大长度变化情况。 ```python def max_width(root): if not root: return 0 width = 0 queue = [(root, 0)] # (node, index) current_index = 0 leftmost_index = 0 rightmost_index = 0 while queue: next_queue = [] for item in queue: node, idx = item if node.left: next_queue.append((node.left, idx*2)) if node.right: next_queue.append((node.right, idx*2+1)) if next_queue: leftmost_index = next_queue[0][1] rightmost_index = next_queue[-1][1] width = max(width, rightmost_index - leftmost_index + 1) queue = next_queue[:] return width ``` 这里采用了稍微不同的做法——不仅保存了节本身还附加了一个索引来帮助确定最左侧和最右侧位置之间的距离差值,进而得到每一行的实际跨度大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值