题目描述
班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
在一个游戏中,需要小朋友坐一个圈,
每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?
小朋友编号为1,2,3,…N
输入
输入第一行,一个整数N(3<N<100000)
接下来一行N个整数,由空格分开。
输出
要求输出一个整数,表示满足条件的最大圈的人数。
样例输入
9
3 4 2 5 3 8 4 6 9
样例输出
4
在网上查找到此题有好多dfs每个点的深度去作差求解,但是我感觉如果数据范围达到极端,而且圈的大小也大到极端,这种情况下就超时了(1e+10的时间复杂度)。也许有好的dfs,至少我看到的那些dfs肯定是超时的,只能说数据太水。
正解:拓扑思想将不可能在环中的小朋友删掉(太残忍了^-^),即入度为0,循环操作即可。剩下的就是一定在某个环中的小朋友了。 然后就可以找每个环了(见代码);
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <cstdio>
#include <string>
#include <stack>
#include <set>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
typedef long long ll;
int a[100010];
int d[100010];//入度
bool del[100010];
int n;
//拓扑思想将不可能在某个环中的点删除(del)
void topu(){
queue<int >p;
//入度为0的点不可能在环中
for(int i=1;i<=n;i++){
if(!d[i]){
del[i]=true;
d[a[i]]--;//删除后继的一个入度
p.push(i);
}
}
while(!p.empty()){
int t=p.front();
p.pop();
int v=a[t];
if(!d[v]){
del[v]=true;
p.push(v);
if(d[a[v]]>0)d[a[v]]--;
}
}
return ;
}
int main()
{
IOS;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
d[a[i]]++;
}
topu();
int maxn=0;
//接下来就只剩下若干个环了
for(int i=1;i<=n;i++){
if(del[i])continue;
del[i]=true;
int t=i,sum=1;
while(a[t]!=i){
sum++;
del[t]=true;//边找边删点,因为这个点不可能在其他环中,所以避免重复循环查找此环
t=a[t];
}
maxn=max(maxn,sum);
}
cout<<maxn<<endl;
getchar();
getchar();
return 0;
}