310. 最小高度树 树的直径重心

  1. 最小高度树

对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。

格式

该图包含 n 个节点,标记为 0 到 n - 1。给定数字 n 和一个无向边 edges 列表(每一个边都是一对标签)。

你可以假设没有重复的边会出现在 edges 中。由于所有的边都是无向边, [0, 1]和 [1, 0] 是相同的,因此不会同时出现在 edges 里。

示例 1:

输入: n = 4, edges = [[1, 0], [1, 2], [1, 3]]

    0
    |
    1
   / \
  2   3 

输出: [1]

示例 2:

输入: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

 0  1  2
  \ | /
    3
    |
    4
    |
    5 

输出: [3, 4]

说明:

 根据树的定义,树是一个无向图,其中任何两个顶点只通过一条路径连接。 换句话说,一个任何没有简单环路的连通图都是一棵树。
树的高度是指根节点和叶子节点之间最长向下路径上边的数量。

通过次数9,990
提交次数29,178


  • 树的重心一定是满足要求的答案
  • 树上最长链的中心节点 ( 可 能 有 2 个 ) \color{red}{(可能有2个)} (2)就是树的重心
  • 树的直径可以两次bfsdfs求出来,再dfs一次找出两端点间的路径,取中间节点即可
#define debug
#ifdef debug
#include 
#endif

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#define show(x...) \
    do { \
       cout << "\033[31;1m " << #x << " -> "; \
       err(x); \
    } while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO{

    char print_f[105];
    void read() {}
    void print() { putchar('\n'); }

    template <typename T, typename... T2>
       inline void read(T &x, T2 &... oth) {
           x = 0;
           char ch = getchar();
           ll f = 1;
           while (!isdigit(ch)) {
               if (ch == '-') f *= -1; 
               ch = getchar();
           }
           while (isdigit(ch)) {
               x = x * 10 + ch - 48;
               ch = getchar();
           }
           x *= f;
           read(oth...);
       }
    template <typename T, typename... T2>
       inline void print(T x, T2... oth) {
           ll p3=-1;
           if(x<0) putchar('-'), x=-x;
           do{
                print_f[++p3] = x%10 + 48;
           } while(x/=10);
           while(p3>=0) putchar(print_f[p3--]);
           putchar(' ');
           print(oth...);
       }
} // namespace FastIO
using FastIO::print;
using FastIO::read;

vector<int> G[MAXN];
bool vis[MAXN];
int U, V, tmax, tmp[MAXN], sz;

class Solution {
public:
    
    void init(int n) {
        U = V = tmax = -1;
        sz = 0;
        memset(vis, false, sizeof(vis));
        for(int i=0; i<=n; i++) G[i].clear();
    }

    void dfs1(int u, int level) {
        // show(u, level, G[u].size());
        if(level >= tmax) {
            tmax = level;
            U = u;
        }
        vis[u] = true;
        for(auto v : G[u]) {
            if(!vis[v]) dfs1(v, level+1);
        }
    }

    void dfs2(int u, int level) {
        // show(u, level);
        if(level >= tmax) {
            tmax = level;
            V = u;
        }
        vis[u] = true;
        for(auto v : G[u])
            if(!vis[v]) dfs2(v, level+1);
    }
    #define ISMID(x, y) (y&1 ? ((y>>1)==x) : ((y>>1)==x || (y>>1|1)==x))
    void dfs3(int u, int level, vector<int>& ans) {
#ifdef debug
        show("dfs3", u, level, tmax);
        if(ISMID(level, tmax)) {
            ans.push_back(u);
        }
#endif
        tmp[++sz] = u;
        if(u == U) {
            ans.push_back(tmp[((tmax+1)/2)]);
            if(!(tmax&1)) ans.push_back(tmp[tmax/2+1]);
#ifdef debug
            for(int i=1; i<=sz; i++) show(tmp[i]);
#endif
            return ;
        }

        vis[u] = true;
        for(auto v : G[u])
            if(!vis[v]) dfs3(v, level+1, ans);
        sz --;
    }
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
        vector<int> ans;
        init(n);
        for(vector<int> ed : edges) {
            int u = ed[0], v = ed[1];
            G[u].push_back(v), G[v].push_back(u);
        }
#ifdef debug
        for(int i=0; i<n; i++) {
            printf("%d:", i);
            for(auto v : G[i])
                printf("->%d ", v);
            printf("\n");
        }
#endif
        dfs1(0, 1);
        tmax = 0;
        memset(vis, false, sizeof(vis));
        dfs2(U, 1);
#ifdef debug
        show(U, V, tmax);
#endif
        memset(vis, false, sizeof(vis));
        dfs3(V, 1, ans);
        return ans;
    }
};

#ifdef debug
signed main() {
    Solution s;
    // vector > vec = { {1, 0}, {1, 2}, {1, 3} };
    // vector > vec = { {0, 3}, {1, 3}, {2, 3}, {4, 3}, {5, 4} };
    // vector > vec = { {3, 0}, {3, 1}, {3, 2}, {3, 4}, {5, 4} };
    vector<vector<int> > vec = { {0, 1}, {1, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6} };
    vector<int> ans = s.findMinHeightTrees(7, vec);
    // show(ans.size());
    for(auto x : ans) show(x);





   return 0;
}

#endif 


你可能感兴趣的:(树的直径,树的重心,矮根,选一个树节点使得dfs深度最小)