对于一个具有树特征的无向图,我们可选择任何一个节点作为根。图因此可以成为树,在所有可能的树中,具有最小高度的树被称为最小高度树。给出这样的一个图,写出一个函数找到所有的最小高度树并返回他们的根节点。
格式
该图包含 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
bfs
或dfs
求出来,再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