L2-026 小字辈

传送门

经过这么多题的反思与整理,现在重新写这种题实在太简单了

CE1DB43BB7F0DAFE94271DD9B2F0007A

柳婼大大这里使用的是BFS,但是我用的是DFS,两者都可以,前者对于初学者可能稍微难写了一点(虽然模板性非常强)。

解题思路

  • 显然建图,而且显然是邻接表,数据量是\(10^5\),邻接表处理得过来

dfs遍历我们建的图,从根节点开始,令根节点的距离为1,用d数组记录距离(深度)(辈分),每个子节点的距离等于父节点的距离加 \(1\)
这题可以与下面的L2-031深入虎穴联系一下

tip:

以往我会采用当前深度与最大深度比较,如果相等会存进答案数组里,如果需要更新的时候,我会先清空数组再把新的数字放进去。但是其实可以先算出来最大深度,再遍历一遍,把符合条件的放进答案数组,可以省去清空数组的开销

这里给出DFS和BFS两种做法

算法一

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

vector<int> f[100010];
bool vis[100010];
int d[100010];

int root;
int n;

void dfs(int u)
{
	vis[u] = true;
	
	for(auto x : f[u])
	{
		if(!vis[x])
		{
			vis[x] = true;
			d[x] = d[u] + 1;
			dfs(x);
		}
	}
	

}


int main()
{
	cin>>n;
	for(int i = 1 ; i <= n ; i++)
	{
		int x;cin>>x;
		if(x == -1) root = i;
		else f[x].push_back(i);
	}
	d[root] = 1;
	dfs(root);
	
	int max_d = 0;
	vector<int> res;
	for(int i = 1 ; i <= n ; i++)	max_d = max(d[i],max_d);
	
    for(int i = 1 ; i <= n ; i++)    if(d[i] == max_d) res.push_back(i);

	cout<<max_d<<endl;
    
	for(int i = 0 ; i < res.size()  ; i ++ )
	{
		cout<<res[i];
		if(i != res.size() - 1) cout<<" ";
	}	
	return 0;
}

算法二

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 100010;
vector<int> adj[N];
int dist[N];
int n,root;

void bfs()
{
	queue<int> q;
	q.push(root);
	dist[root] = 1;
	while(!q.empty())
	{
		int t = q.front();
		q.pop();
		for(int son : adj[t])
		{
			if(dist[son] == 0)
			{
				dist[son] = dist[t] + 1;
				q.push(son);
			}
		}
	}	
}

int main()
{
	cin>>n;
	for(int i = 1 ; i <= n ; i++)
	{
		int p;cin>>p;
		if(p == -1) root = i;
		else adj[p].push_back(i);
		
	}
	bfs();
	int max_d=0;
	for(int i = 1; i <= n ; i++)
	{
		max_d = max(max_d,dist[i]);
	}
	
	cout<<max_d<<endl;
	
	vector<int> res;
	for(int i = 1 ; i <= n ; i++)
	{
		if(dist[i] == max_d)
		{
			res.push_back(i);
		}
	}
	
	for(int i = 0 ; i < res.size() ; i ++)
	{
		cout<<res[i];
		if(i != res.size() - 1 ) cout<<" ";
	}
	
	
	return 0;
}

算法三:记忆化搜索

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 100010;
int f[N]; // 记录父辈
int d[N]; // 记忆化搜索:记录每个节点的深度

// 递归求深度
int getdepth(int u)
{
    // 如果是老祖宗(父辈为 -1),深度为 1
    if (f[u] == -1)
    {
        return 1;
    }
    // 如果已经算过了,直接返回,避免重复计算
    if (d[u] != 0)
    {
        return d[u];
    }
    // 否则:我的深度 = 我父亲的深度 + 1
    d[u] = getdepth(f[u]) + 1;
    return d[u];
}

int main()
{
    int n;
    if (!(cin >> n))
    {
        return 0;
    }

    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        f[i] = x;
    }

    int max_depth = -1;
    // 1. 先计算出所有人的深度,并找出最大深度是多少
    for (int i = 1; i <= n; i++)
    {
        int current_depth = getdepth(i);
        if (current_depth > max_depth)
        {
            max_depth = current_depth;
        }
    }

    // 2. 统计所有处于最大深度的成员编号
    vector<int> res;
    for (int i = 1; i <= n; i++)
    {
        if (d[i] == max_depth)
        {
            res.push_back(i);
        }
    }

    // 3. 按要求输出
    cout << max_depth << endl;
    for (int i = 0; i < res.size(); i++)
    {
        cout << res[i] << (i == res.size() - 1 ? "" : " ");
    }
    cout << endl;

    return 0;
}
posted @ 2026-03-16 20:12  shuiwangrenjia  阅读(29)  评论(0)    收藏  举报