L2-026 小字辈 (25 分) 记忆化搜索

7-4 小字辈
本题给定一个庞大家族的家谱,要请你给出最小一辈的名单。

输入格式:
输入在第一行给出家族人口总数 N(不超过 100 000 的正整数) —— 简单起见,我们把家族成员从 1 到 N 编号。随后第二行给出 N 个编号,其中第 i 个编号对应第 i 位成员的父/母。家谱中辈分最高的老祖宗对应的父/母编号为 -1。一行中的数字间以空格分隔。

输出格式:
首先输出最小的辈分(老祖宗的辈分为 1,以下逐级递增)。然后在第二行按递增顺序输出辈分最小的成员的编号。编号间以一个空格分隔,行首尾不得有多余空格。

输入样例:
9
2 6 5 5 -1 5 6 4 7
输出样例:
4
1 9

从子节点向上搜索深度并记录,找到最大深度
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int f[N],d[N];
int dfs(int u){
	if(d[u])return d[u];
	if(f[u]==-1)return d[u]=1;
	return d[u]=dfs(f[u])+1;
}
int main()
{
	int n;cin>>n;
	memset(f,-1,sizeof f);
	for(int i=1;i<=n;++i)cin>>f[i];
	int ma=0;
	for(int i=1;i<=n;++i){
		dfs(i);
		ma=max(ma,d[i]);
	}
	cout<<ma<<endl;
	bool flag=true;
	for(int i=1;i<=n;++i){
		if(d[i]==ma){
			if(flag){
				cout<<i;flag=false;
			}
			else cout<<" "<<i; 
		}
	}
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int f[N],d[N],n,x,ma,cnt;
int find(int x)
{
	if(d[x])return d[x];
	if(f[x]==-1)return d[x]=1;
	d[f[x]]=find(f[x]);
    return d[f[x]]+1;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>x;f[i]=x;
	}
	for(int i=1;i<=n;++i){
		d[i]=find(i);
		if(d[i]>ma)ma=d[i],cnt=1;
		else if(d[i]==ma)cnt++;
	}
	cout<<ma<<endl;
	for(int i=1;i<=n;++i)
	{
		if(d[i]==ma)
		{
			cnt--;
			if(cnt)cout<<i<<" ";
			else cout<<i;
		}
	}
	return 0;
} 
先搜索出最大深度,在从上向下搜索符合最大深度的子节点
#include <bits/stdc++.h>

using namespace std;
const int N=100005;
int n,f[N],z,a[N],p;
vector<int> e[N];
int ans;
queue<int> q;

int dfs(int u)
{
	int t=0;
	for(int i=0;i<e[u].size();++i)
	{
		t=max(dfs(e[u][i]),t);
	}
	return t+1;
}

void df(int u,int t)
{
	if(t==ans)a[p++]=u;
	for(int i=0;i<e[u].size();++i)
	{
		df(e[u][i],t+1);
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		int x;cin>>x;
		f[i]=x;
		if(x==-1)
		{
			z=i;continue;
		}
		e[x].push_back(i);
	}
	ans=dfs(z); 
	cout<<ans<<endl;
	df(z,1);
	sort(a,a+p);
	for(int i=0;i<p;++i)
	{
		if(i!=p-1)cout<<a[i]<<" ";
		else cout<<a[i];
	}
	return 0;
}
posted @ 2022-11-17 23:02  林动  阅读(26)  评论(0编辑  收藏  举报