題目描述
班裏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;
}