藍橋杯訓練——[藍橋杯][2018年第九屆真題]小朋友崇拜圈

題目鏈接:https://www.dotcpp.com/oj/problem2283.html

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

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章