小朋友崇拜圈(巧妙递归)

小朋友崇拜圈

班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
在一个游戏中,需要小朋友坐一个圈,
每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?

小朋友编号为1,2,3,…N
输入第一行,一个整数N(3<N<100000)
接下来一行N个整数,由空格分开。

要求输出一个整数,表示满足条件的最大圈的人数。

例如:
输入:
9
1 2 3 4 5 6 7 8 9
3 4 2 5 3 8 4 6 9

则程序应该输出:
4

解释:
如图p1.png所示,崇拜关系用箭头表示,红色表示不在圈中。
显然,最大圈是[2 4 5 3] 构成的圈

再例如:
输入:
30
22 28 16 6 27 21 30 1 29 10 9 14 24 11 7 2 8 5 26 4 12 3 25 18 20 19 23 17 13 15

程序应该输出:
16

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

一开始就直接想到并查集,但是因没有办法避免重复而超时,后来看了大佬的代码,就感觉还是自己太笨T.T

#include<iostream>
#include<vector>
using namespace std;
#define N 100005
int a[N];
int num[N];
int vis[N];
int n,ans,cnt;
int dfs(int x,int res)
{
	vis[x]=res;        //对应每个圈的起点
	num[x]=++cnt;      //每个数对应一个编号,这个圈的最大长度等于最后一个数的编号减去第一个数的编号+1
	int y=a[x];        //y为x崇拜的人
	if(vis[y]==res)    //若y崇拜的人恰好是起点的人
	{
		ans=max(ans,num[x]-num[y]+1);      //更新最大圈的长度
	}
	else
		dfs(y,res);        //递归找到终点
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])      //若数字在之前的圈没出现过,递归进入新圈
			dfs(i,i);
	}
	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43693379/article/details/88757716