蓝桥杯训练——[蓝桥杯][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;
}

 

 

 

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