- 推理类问题,一定要注意排除法的应用,即推到最后剩下来的对象一定符合题意,不需要再付出代价去验证
- 如果由单个点构成的强连通分量满足把它删除后入度为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;
}