#1021. Deepest Root【DFS / BFS 遍历树 + 树的深度】

原题链接

Problem Description:

A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N N N ( ≤ 1 0 4 \leq 10^4 104) which is the number of nodes, and hence the nodes are numbered from 1 to N N N. Then N − 1 N−1 N1 lines follow, each describes an edge by given the two adjacent nodes’ numbers.

Output Specification:

For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print Error: K components where K is the number of connected components in the graph.

Sample Input 1:

5
1 2
1 3
1 4
2 5

Sample Output 1:

3
4
5

Sample Input 2:

5
1 3
1 4
2 5
3 4

Sample Output 2:

Error: 2 components

Problem Analysis:

数据范围为 1 ≤ N ≤ 1 0 4 1\leq N\leq 10^4 1N104,并且时限为 2s,因此可以考虑使用暴力枚举每一个节点作为根,然后进行树的遍历,并不断更新最深的高度。开一个存储最深根节点的数组,如果后续节点的高度与当前更新到的最深高度相等,就将这个节点假如数组中;若出现了更高的高度,就将数组清空,重新累计。

这里可以使用 BFS 或者 DFS 来遍历整颗树,理论上来说两种方案,对于每一个根的遍历,每个节点都只会访问一次,因此都是 O ( n 2 ) O(n^2) O(n2) 的。但 AcWing 上数据过强,最后一个点卡掉了我的 BFS 做法。

Code

BFS
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int N = 10010, M = N * 2;

int n, maxh;
int p[N];
int h[N], e[M], ne[M], idx;
int q[N], dist[N];
bool st[N];
vector<int> ans;

int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

void add(int a, int b)
{
	e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void bfs(int root)
{
	memset(dist, 0x3f, sizeof dist);
	memset(st, 0, sizeof st);
	int hh = 0, tt = -1;
	dist[root] = 0;
	st[root] = true;
	q[ ++ tt] = root;

	int maxtmp = -1;
	while (hh <= tt)
	{
		auto t = q[hh ++ ];
		for (int i = h[t]; ~i; i = ne[i])
		{
			int j = e[i];
			if (dist[j] > dist[t] + 1)
			{
				dist[j] = dist[t] + 1;
				if (dist[j] > maxtmp) maxtmp = dist[j];
				if (!st[j])
				{
					st[j] = true;
					q[ ++ tt] = j;	
				}
			}
		}
	}
	if (maxtmp > maxh) 
	{
		maxh = maxtmp;
		ans.clear();
		ans.push_back(root);
	}
	else if (maxtmp == maxh) ans.push_back(root);
}

int main()
{
	cin >> n;
	memset(h, -1, sizeof h);
	for (int i = 1; i <= n; i ++ ) p[i] = i; // 初始化并查集

	for (int i = 0; i < n - 1; i ++ ) // 建图,只有n-1条边
	{
		int a, b;
		scanf("%d%d", &a, &b);
		add(a, b), add(b, a);
		if (find(a) != find(b)) p[find(a)] = find(b);
	}
	
	int comp = 0; // 找到每个连通分量的代表元素,累计代表元素数量,如果为1,说明是树,否则是图
	for (int i = 1; i <= n; i ++ )
		if (p[i] == i)
			comp ++ ;

	if (comp > 1) printf("Error: %d components\n", comp);
	else
	{
		maxh = -1;
		for (int i = 1; i <= n; i ++ ) // 以每个点都作为一个根进行 BFS
			bfs(i);

		sort(ans.begin(), ans.end());
		for (int i = 0; i < ans.size(); i ++ )
			cout << ans[i] << endl;
	}
	return 0;
}
DFS
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int N = 10010, M = N * 2;

int n, maxh;
int p[N];
int h[N], e[M], ne[M], idx;
vector<int> ans;

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int dfs(int u, int father) // 返回从 当前节点往下搜,最高的高度为多少
{
    int depth = 0;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == father) continue;
        depth = max(depth, dfs(j, u) + 1);
    }
    return depth;
}

int main()
{
    cin >> n;
    memset(h, -1, sizeof h);

    for (int i = 1; i <= n; i ++ ) p[i] = i;

    for (int i = 0; i < n - 1; i ++ )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
        if (find(a) != find(b)) p[find(a)] = find(b);
    }

    int comp = 0;
    for (int i = 1; i <= n; i ++ )
        if (p[i] == i)
            comp ++ ;
    
    if (comp > 1) printf("Error: %d components\n", comp);
    else
    {
        maxh = -1;
        for (int i = 1; i <= n; i ++ )
        {
            int depth = dfs(i, -1);
            if (depth > maxh) 
            {
                maxh = depth;
                ans.clear();
                ans.push_back(i);
            }
            else if (depth == maxh) ans.push_back(i);
        }

        sort(ans.begin(), ans.end());
        for (int i = 0; i < ans.size(); i ++ ) 
            cout << ans[i] << endl;
    } 
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值