BZOJ2438

强连通。

只需要访问一个点就可知道它那个连通分量的所有点的情况,而入度为0的连通分量才是需要优先确认的目标,所以只需要计算有几个入度为0的连通分量。

如果在整个图中,有一个点(这个连通分量里只有一个点!!!)它所连的点都能被其它点访问到(入度大于1),就可以不访问它也可以知道它身份(除了它以外的点都确认了),所以可以少访问一次。

这道题的答案是1-ans/n

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define min(u1,u2) (u1<u2?u1:u2)
struct mod{int x,y,next;};
mod q[300005],w[300005];
int len=0,id=0,tp=0,num=0;
int dfn[1000005];
int low[1000005];
int sta[1000005];
bool vis[1000005];
int home[1000005];
int first[1000005];
int in[1000005];
int size[1000005];
void ins(int x,int y)
{
len++;
q[len].x=x;
q[len].y=y;
q[len].next=first[x];
first[x]=len;
}
void dfs(int x)
{
dfn[x]=low[x]=++id;
vis[x]=true;
sta[++tp]=x;
for (int i=first[x];i!=0;i=q[i].next)
{
int y=q[i].y;
if (dfn[y]==-1)
{
dfs(y);
low[x]=min(low[x],low[y]);
}
else
if (vis[y]==true)
{
low[x]=min(low[x],dfn[y]);
}
}
if (dfn[x]==low[x])
{
num++;
while(1)
{
int i=sta[tp--];
vis[i]=false;
home[i]=num;
size[num]++;
if (i==x)break;
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
memset(first,0,sizeof(first));
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,y);
}
memset(dfn,-1,sizeof(dfn));
memset(low,0,sizeof(low));
for (int i=1;i<=n;i++)
{
if (dfn[i]==-1)
dfs(i);
}
//for (int i=1;i<=n;i++)
//printf("i:%d h:%d\n",i,home[i]);
//system("pause");
memset(first,0,sizeof(first));
len=0;
for (int i=1;i<=m;i++)
{
if (home[q[i].x]!=home[q[i].y])
{
len++;
w[len].x=home[q[i].x];
w[len].y=home[q[i].y];
w[len].next=first[home[q[i].x]];
first[home[q[i].x]]=len;
in[home[q[i].y]]++;
}
}
int ans=0;
bool tf=true;
for (int i=1;i<=num;i++)
{
if (in[i]==0)
{
ans++;
if (tf==false||size[i]>1)continue;
bool tff=true;
for (int j=first[i];j!=0;j=w[j].next)
{
int y=w[j].y;
if (in[y]<=1){tff=false;break;}
}
if (tff==true)
{tf=false;ans--;}
}
}
double p=(double)ans;
printf("%.6lf\n",1-p/n);
}

posted on 2016-11-10 13:40  Notok  阅读(129)  评论(0编辑  收藏

导航