很神奇的一道题啊。。
一开始以为是什么奇奇怪怪的题。。
然后发现是一个强联通+奇奇怪怪的做法
首先,强联通是肯定的。。因为你一个环你只需要问一个点,就可以推出这个环全部的人的状况
然后呢,你就将他缩点
然后呢,我们又知道只有入度为0的块是需要被询问的,因为不为1的块的状态又可以安全地推出来
于是就算一下又多少个入度为0的点
当然这题是不是这样就结束了呢?
当然不是!
还有一种情况,那就是又n个人,你问了n-1个人了,那么最后一个人当然不用问!
那么这是一种什么情况呢
首先,这个块只有一个人
其次,这个块所连出去的边相当于没有连
也就是他连的块还有别的块相连
于是就可以了
#include<cstdio>
#include<cstring>
const int M=300005;
const int N=100005;
int n,m;
struct qq
{
int x,y,last;
}s[M],s1[M];int num,last[N];
int num1,last1[N];
void init (int x,int y)
{
num++;
s[num].x=x;s[num].y=y;
s[num].last=last[x];
last[x]=num;
}
int dfn[N],low[N],belong[N],cnt=0,id=0;
int sta[N],ooo=0;
bool in[N];
int lalal[N];//这个块有多少人
int mymin (int x,int y){return x<y?x:y;}
void dfs (int x)
{
sta[++ooo]=x;in[x]=true;
dfn[x]=low[x]=++id;
for (int u=last[x];u!=-1;u=s[u].last)
{
int y=s[u].y;
if (dfn[y]==-1)
{
dfs(y);
low[x]=mymin(low[x],low[y]);
}
else if (in[y]) low[x]=mymin(low[x],dfn[y]);
}
if (low[x]==dfn[x])
{
cnt++;
int now;
do
{
now=sta[ooo--];
belong[now]=cnt;
in[now]=false;
lalal[cnt]++;
}while (now!=x);
}
}
int du[N];
bool mark[N];
void init2 (int x,int y)
{
du[y]++;
num1++;
s1[num1].x=x;s1[num1].y=y;
s1[num1].last=last1[x];
last1[x]=num1;
}
void rebt ()
{
memset(mark,false,sizeof(mark));
for (int u=1;u<=n;u++)
{
for (int i=last[u];i!=-1;i=s[i].last)
{
int y=s[i].y;
if (belong[u]==belong[y]) continue;
if (mark[belong[y]]==true) continue;
mark[belong[y]]=true;
init2(belong[u],belong[y]);
}
for (int i=last[u];i!=-1;i=s[i].last)
mark[belong[s[i].y]]=false;
}
return ;
}
bool Jud (int x)
{
if (du[x]!=0&&lalal[x]!=1) return false;
for (int u=last1[x];u!=-1;u=s1[u].last)
{
int y=s1[u].y;
if (du[y]==1) return false;
}
return true;
}
int main()
{
num1=0;memset(last1,-1,sizeof(last1));
memset(in,false,sizeof(in));
num=0;memset(last,-1,sizeof(last));
scanf("%d%d",&n,&m);
for (int u=1;u<=m;u++)
{
int x,y;
scanf("%d%d",&x,&y);
init(x,y);
}
memset(dfn,-1,sizeof(dfn));
memset(in,false,sizeof(in));
for (int u=1;u<=n;u++)
if (dfn[u]==-1)
dfs(u);
rebt();
//for (int u=1;u<=cnt;u++) printf("%d ",du[u]);
int ans=0;
for (int u=1;u<=cnt;u++)
if (du[u]==0) ans++;
for (int u=1;u<=cnt;u++)
if (Jud(u))
{ans--;break;}
printf("%.6lf\n",1-(double)ans/(double)n);
return 0;
}