[中山市选]

  • 推理类问题,一定要注意排除法的应用,即推到最后剩下来的对象一定符合题意,不需要再付出代价去验证
  • 如果由单个点构成的强连通分量满足把它删除后入度为0的强连通分量不增加,答案就可以+1
#include <bits/stdc++.h>
#define int long long
using namespace std;
vector<int>a[500005],scc[500005];
int u[500005],v[500005],d[500005];
int dfn[500005],low[500005],tot,cnt,id[500005];
bool ins[500005];
stack<int>s;
void tarjan(int n1)
{
	dfn[n1]=low[n1]=++tot;
	s.push(n1);
	ins[n1]=true;
	for(int i=0;i<a[n1].size();i++)
	{
		if(!dfn[a[n1][i]])
		{
			tarjan(a[n1][i]);
			low[n1]=min(low[n1],low[a[n1][i]]);
		}
		else if(ins[a[n1][i]]==true)
		{
			low[n1]=min(low[n1],dfn[a[n1][i]]);
		}
	}
	if(dfn[n1]==low[n1])
	{
		cnt++;
		while(s.top()!=n1)
		{
			id[s.top()]=cnt;
			scc[cnt].push_back(s.top());
			ins[s.top()]=false;
			s.pop();
		}
		id[n1]=cnt;
		scc[cnt].push_back(n1);
		ins[n1]=false;
		s.pop();
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		cin>>u[i]>>v[i];
		a[u[i]].push_back(v[i]);
	}
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])
		{
			tarjan(i);
		}
	}
	for(int i=1;i<=m;i++)
	{
		if(id[u[i]]!=id[v[i]])
		{
			d[id[v[i]]]++;
		}
	}
	int sum=n;
	bool f=false;
	for(int i=1;i<=cnt;i++)
	{
		sum-=(d[i]==0);
		if(d[i]==0&&scc[i].size()==1)
		{
			bool pd=true;
			int u=scc[i][0];
			for(int v:a[u])
			{
				d[id[v]]--;
				if(d[id[v]]==0)
				{
					pd=false;
				}
			}
			f|=pd;
			for(int v:a[u])
			{
				d[id[v]]++;
			}
		}
	}
	sum+=f;
	cout<<fixed<<setprecision(6)<<1.0*sum/n<<endl;
	return 0;
}
posted @ 2025-05-02 14:19  D06  阅读(9)  评论(0)    收藏  举报
//雪花飘落效果