洛谷 p5536 题解

题目链接:https://www.luogu.com.cn/problem/P5536
此题为树的dfs的一个应用。

思路

  1. 树 dfs时,可以计算每个点的深度。
    如图所示
  2. 可以多次dfs,从而找到不同的信息。

代码片断

  1. 2次dfs找直径/中心
int maxLen = INT_MIN;//直径
int q;//最远点
vector<int> dist(n+1);//每个点的深度
vector<int> pathPrev(n+1);//直径找父
function<void(int, int)> dfs = [&](int u, int fa) {
    for (auto v : G[u]) {
        if (v == fa)continue;
        dist[v] = dist[u] + 1;
        pathPrev[v] = u;
        if (maxLen < dist[v]) { maxLen = dist[v]; q = v; }
        dfs(v, u);
    }
};
dfs(1, 0);//任意点找最远点
int ret1 = q;
dist[q] = 0;
maxLen = INT_MIN;
dfs(q, 0);//最远点找另一最远点
  1. 找直径中心
int midPoint = q;
for (int i = 0; i < (maxLen+1)/ 2; ++i) 
  midPoint = pathPrev[midPoint];
  1. 每个点到叶子点的最远距离
vector<int> maxDeep(n + 1);//当前点能到达的最大深度
vector<int> deep(n + 1);   //当前点的深度  这个与前面的dist意义相同
vector<int> eachPointToLeafLen(n+1);
function<void(int, int)>  dfs3= [&](int u, int fa) {
  maxDeep[u] = deep[u];
  for (auto v : G[u]) {
    if (v != fa) continue;
    deep[v] = deep[u] + 1;//子点的深度
    dfs3(v, u);
    maxDeep[u] = max(maxDeep[u],maxDeep[v]);//此点最深由子深决定
  }
  eachPointToLeafLen[u] = (maxDeep[u] - deep[u]);//此点到最深的叶子长度
};
dfs3(midPoint, -1);

完整代码

#include <iostream>
#include <cassert>
#include <iomanip>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <climits>
#include <functional>
#include <list>
#include <cstdlib>
#include <set>
#include <stack>
#include <sstream>
#include <numeric>
#include <map>
#include <algorithm>
#include <bitset>

#define endl "\n"
#define i64 long long
#define ui64 unsigned long long
#define INF 0x3f3f3f3f
#define MZ(arr) memset(arr,0,sizeof(arr))
#define MS(arr,val) memset(arr,val,sizeof(arr))



using namespace std;

namespace SLOVER {
    void slove() {
        int n, k,u,v;
        cin >> n >> k;
        vector<vector<int>> G(n + 1);
        for (int i = 1; i < n; ++i) {
            cin >> u >> v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
      vector<int> pathPrev(n+1);

      int maxLen = INT_MIN;
      int q;
      vector<int> dist(n+1);
      auto dfs2FindDiameter = [&]() {
        function<void(int, int)> dfs = [&](int u, int fa) {
          for (auto v : G[u]) {
            if (v != fa) {
              dist[v] = dist[u] + 1;
              pathPrev[v] = u;
              if (maxLen < dist[v]) {
                maxLen = dist[v];
                q = v;
              }
              dfs(v, u);
            }
          }
        };
        dfs(1, 0);
        int ret1 = q;
        dist[q] = 0;
        maxLen = INT_MIN;
        dfs(q, 0);
      };

      dfs2FindDiameter();

    int midPoint = q;
    for (int i = 0; i < (maxLen+1)/ 2; ++i) {
      midPoint = pathPrev[midPoint];
    }

    vector<int> maxDeep(n + 1);//当前点能到达的最大深度
    vector<int> deep(n + 1);//当前点的深度
    vector<int> eachPointToLeafLen;
    function<void(int, int)> calcDeep = [&](int u, int fa) {
      maxDeep[u] = deep[u];
      for (auto v : G[u]) {
        if (v != fa) {
          deep[v] = deep[u] + 1;
          calcDeep(v, u);
          maxDeep[u] = max(maxDeep[u],maxDeep[v]);
        }
      }
      eachPointToLeafLen.push_back(maxDeep[u] - deep[u]);
    };
    calcDeep(midPoint, -1);
    sort(eachPointToLeafLen.begin(), eachPointToLeafLen.end(), std::greater<int>());

    int ret = 0;
    for (int i = k; i < n; ++i)ret = max(ret, eachPointToLeafLen[i] + 1);
    cout << ret << endl;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int  t = 1;
    while (t--) { SLOVER::slove(); }
    return 0;
}
posted @ 2023-01-05 13:36  传说中的水牛  阅读(35)  评论(0编辑  收藏  举报