传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2438
问题转化为,找最小的人找到所有的点。
发现一个点,就可以发现他所在的强连通分量的所有点,那么我们跑一遍强连通分量缩点,建一个新图,找到所有入度为0的分量的数量就是我们最少需要找的人。
但是!!还没有完!!
因为如果一个连通分量里面只有一个点,而且这个点的入度为0,且他连到的所有连通分量都有其他人可以连到他,这样的点,我们不需要去访问他,只需要把其他的点访问完自然可以知道他是谁,所以这种情况ans需要减去1!
code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int maxm=300010;
struct node
{
int x,y,next;
}a[maxm],b[maxm];
int len1,last1[maxn];
int len2,last2[maxn];
int ru[maxn],chu[maxn];
void ins1(int x,int y)
{
len1++; a[len1].x=x;a[len1].y=y;
a[len1].next=last1[x];last1[x]=len1;
}
void ins2(int x,int y)
{
len2++; b[len2].x=x;b[len2].y=y;
b[len2].next=last2[x];last2[x]=len2;
ru[y]++;
}
int low[maxn],dfn[maxn],id;
int sta[maxn],top; bool insta[maxn];
int bl[maxn],scc,sum[maxn];
int n,m;
void dfs(int x)
{
low[x]=dfn[x]=++id;
sta[++top]=x; insta[x]=true;
for(int k=last1[x];k;k=a[k].next)
{
int y=a[k].y;
if(dfn[y]==-1)
{
dfs(y);
low[x]=min(low[x],low[y]);
}
else
{
if(insta[y])
low[x]=min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x])
{
int i; scc++;
do{
i=sta[top--];
bl[i]=scc;
insta[i]=false;
sum[scc]++;
}while(i!=x);
}
}
bool vis[maxn];
void rebuild()
{
memset(vis,false,sizeof(vis));//去重
for(int x=1;x<=n;x++)
{
for(int k=last1[x];k;k=a[k].next)
{
int y=a[k].y;
int u=bl[x],v=bl[y];
if(u!=v && vis[v]==false)
{
ins2(u,v);
vis[v]=true;
}
}
for(int k=last1[x];k;k=a[k].next)
{
int y=a[k].y;
int u=bl[x],v=bl[y];
if(u!=v)
{
vis[v]=false;
}
}
}
}
bool check(int x)
{
if(ru[x]!=0 || sum[x]!=1) return false;//如果一个点(联通分量)入度为0,且里面只有一个点
for(int k=last2[x];k;k=b[k].next)
{
int y=b[k].y;
if(ru[y]<=1) return false;//并且他连出去的所有点都不止一个入度(就是不止他能连到)
}
return true;//那么就不需要访问他就可以知道他是谁
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v;scanf("%d%d",&u,&v);
ins1(u,v);
}
len1=len2=scc=id=top=0;
memset(dfn,-1,sizeof(dfn));
for(int i=1;i<=n;i++)
if(dfn[i]==-1)
dfs(i);
rebuild();
int ans=0;
for(int i=1;i<=scc;i++)
if(ru[i]==0)
ans++;
for(int i=1;i<=scc;i++)
if(ru[i]==0 && check(i))
{
ans--;
break;
}
printf("%.6lf\n",1.0-(double)(ans)/double(n));
return 0;
}